From 8bacc74d8bdc1882a3faa47eeac7c6c3d2422f23 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 3 Feb 2018 22:52:35 +0300 Subject: [PATCH] Request dialog list entries when needed. Also save the original server-side int32 date in HistoryItems. --- Telegram/SourceFiles/apiwrap.cpp | 186 +++++++++++------ Telegram/SourceFiles/apiwrap.h | 5 + Telegram/SourceFiles/boxes/confirm_box.cpp | 4 +- .../boxes/edit_participant_box.cpp | 8 +- .../boxes/peer_list_controllers.cpp | 6 +- Telegram/SourceFiles/boxes/send_files_box.cpp | 6 +- Telegram/SourceFiles/boxes/sessions_box.cpp | 14 +- .../calls/calls_box_controller.cpp | 7 +- Telegram/SourceFiles/core/file_utilities.cpp | 5 +- Telegram/SourceFiles/core/file_utilities.h | 2 +- Telegram/SourceFiles/core/utils.cpp | 26 +-- Telegram/SourceFiles/core/utils.h | 22 +- Telegram/SourceFiles/data/data_drafts.cpp | 29 ++- Telegram/SourceFiles/data/data_drafts.h | 24 ++- Telegram/SourceFiles/data/data_feed.cpp | 36 +++- Telegram/SourceFiles/data/data_feed.h | 2 + Telegram/SourceFiles/data/data_peer.h | 4 +- .../SourceFiles/data/data_peer_values.cpp | 23 +-- .../SourceFiles/dialogs/dialogs_entry.cpp | 18 +- Telegram/SourceFiles/dialogs/dialogs_entry.h | 4 +- .../dialogs/dialogs_inner_widget.cpp | 15 +- .../SourceFiles/dialogs/dialogs_layout.cpp | 14 +- .../admin_log/history_admin_log_inner.cpp | 6 +- .../admin_log/history_admin_log_item.cpp | 42 ++-- Telegram/SourceFiles/history/history.cpp | 195 ++++++------------ Telegram/SourceFiles/history/history.h | 59 +++++- .../history/history_inner_widget.cpp | 47 +++-- Telegram/SourceFiles/history/history_item.cpp | 37 ++-- Telegram/SourceFiles/history/history_item.h | 14 +- .../history/history_item_components.h | 4 +- .../history/history_media_types.cpp | 2 +- .../SourceFiles/history/history_message.cpp | 123 ++++++----- .../SourceFiles/history/history_message.h | 28 +-- .../SourceFiles/history/history_service.cpp | 37 ++-- .../SourceFiles/history/history_service.h | 10 +- .../SourceFiles/history/history_widget.cpp | 11 +- .../history/view/history_view_element.cpp | 18 +- .../history/view/history_view_element.h | 7 +- .../history/view/history_view_list_widget.cpp | 10 +- .../history/view/history_view_message.cpp | 20 +- .../history/view/history_view_message.h | 4 +- .../info/media/info_media_list_widget.cpp | 6 +- .../inline_bots/inline_bot_send_data.cpp | 6 +- Telegram/SourceFiles/mainwidget.cpp | 12 +- .../media/player/media_player_widget.cpp | 25 ++- Telegram/SourceFiles/mediaview.cpp | 44 ++-- .../SourceFiles/overview/overview_layout.cpp | 24 ++- .../SourceFiles/overview/overview_layout.h | 5 +- .../window/notifications_manager.cpp | 4 +- .../SourceFiles/window/window_controller.cpp | 8 +- 50 files changed, 719 insertions(+), 549 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 7bf60421b..17feed211 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -377,24 +377,6 @@ void ApiWrap::requestDialogEntry(not_null feed) { auto peers = QVector( 1, MTP_inputDialogPeerFeed(MTP_int(feed->id()))); - if (feed->channelsLoaded()) { - const auto &channels = feed->channels(); - peers.reserve(channels.size() + 1); - for (const auto history : feed->channels()) { - peers.push_back(MTP_inputDialogPeer(history->peer->input)); - } - } else { - request(MTPmessages_GetDialogs( - MTP_flags(MTPmessages_GetDialogs::Flag::f_feed_id), - MTP_int(feed->id()), - MTP_int(0), // offset_date - MTP_int(0), // offset_id - MTP_inputPeerEmpty(), // offset_peer - MTP_int(Data::Feed::kChannelsLimit) - )).done([=](const MTPmessages_Dialogs &result) { - // applyFeedChannels(result); - }).send(); - } request(MTPmessages_GetPeerDialogs( MTP_vector(std::move(peers)) )).done([=](const MTPmessages_PeerDialogs &result) { @@ -405,6 +387,27 @@ void ApiWrap::requestDialogEntry(not_null feed) { }).send(); } +//void ApiWrap::requestFeedDialogsEntries(not_null feed) { +// if (_dialogFeedRequests.contains(feed)) { +// return; +// } +// _dialogFeedRequests.emplace(feed); +// +// request(MTPmessages_GetDialogs( +// MTP_flags(MTPmessages_GetDialogs::Flag::f_feed_id), +// MTP_int(feed->id()), +// MTP_int(0), // offset_date +// MTP_int(0), // offset_id +// MTP_inputPeerEmpty(), // offset_peer +// MTP_int(Data::Feed::kChannelsLimit) +// )).done([=](const MTPmessages_Dialogs &result) { +// applyFeedDialogs(feed, result); +// _dialogFeedRequests.remove(feed); +// }).fail([=](const RPCError &error) { +// _dialogFeedRequests.remove(feed); +// }).send(); +//} + void ApiWrap::requestDialogEntry(not_null history) { if (_dialogRequests.contains(history)) { return; @@ -417,43 +420,7 @@ void ApiWrap::requestDialogEntry(not_null history) { MTP_vector(std::move(peers)) )).done([=](const MTPmessages_PeerDialogs &result) { applyPeerDialogs(result); - - if (history->lastMessage()) { - if (!history->chatsListDate().isNull() - && history->loadedAtBottom()) { - if (const auto channel = history->peer->asChannel()) { - const auto inviter = channel->inviter; - if (inviter != 0 - && history->chatsListDate() <= channel->inviteDate - && channel->amIn()) { - if (const auto from = App::userLoaded(inviter)) { - history->insertJoinedMessage(true); - } - } - } - } - history->updateChatListExistence(); - } else { - if (const auto chat = history->peer->asChat()) { - if (!chat->haveLeft()) { - Local::addSavedPeer( - history->peer, - history->chatsListDate()); - } - } else if (const auto channel = history->peer->asChannel()) { - const auto inviter = channel->inviter; - if (inviter != 0 && channel->amIn()) { - if (const auto from = App::userLoaded(inviter)) { - history->unloadBlocks(); - history->addNewerSlice(QVector()); - history->insertJoinedMessage( - true); - } - } - } else { - App::main()->deleteConversation(history->peer, false); - } - } + historyDialogEntryApplied(history); _dialogRequests.remove(history); }).fail([=](const RPCError &error) { _dialogRequests.remove(history); @@ -486,6 +453,95 @@ void ApiWrap::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) { _session->data().sendHistoryChangeNotifications(); } +void ApiWrap::historyDialogEntryApplied(not_null history) { + if (!history->lastMessage()) { + if (const auto chat = history->peer->asChat()) { + if (!chat->haveLeft()) { + Local::addSavedPeer( + history->peer, + history->chatsListDate()); + } + } else if (const auto channel = history->peer->asChannel()) { + const auto inviter = channel->inviter; + if (inviter != 0 && channel->amIn()) { + if (const auto from = App::userLoaded(inviter)) { + history->unloadBlocks(); + history->addNewerSlice(QVector()); + history->insertJoinedMessage(true); + } + } + } else { + App::main()->deleteConversation(history->peer, false); + } + return; + } + + if (!history->chatsListDate().isNull() + && history->loadedAtBottom()) { + if (const auto channel = history->peer->asChannel()) { + const auto inviter = channel->inviter; + if (inviter != 0 + && history->chatsListDate() <= ParseDateTime(channel->inviteDate) + && channel->amIn()) { + if (const auto from = App::userLoaded(inviter)) { + history->insertJoinedMessage(true); + } + } + } + } + history->updateChatListExistence(); +} + +void ApiWrap::applyFeedDialogs( + not_null feed, + const MTPmessages_Dialogs &dialogs) { + const auto [dialogsList, messagesList] = [&] { + const auto process = [&](const auto &data) { + App::feedUsers(data.vusers); + App::feedChats(data.vchats); + return std::make_tuple(&data.vdialogs.v, &data.vmessages.v); + }; + switch (dialogs.type()) { + case mtpc_messages_dialogs: + return process(dialogs.c_messages_dialogs()); + + case mtpc_messages_dialogsSlice: + LOG(("API Error: " + "Unexpected dialogsSlice in feed dialogs list.")); + return process(dialogs.c_messages_dialogsSlice()); + } + Unexpected("Type in DialogsWidget::dialogsReceived"); + }(); + + App::feedMsgs(*messagesList, NewMessageLast); + + auto channels = std::vector>(); + channels.reserve(dialogsList->size()); + for (const auto &dialog : *dialogsList) { + switch (dialog.type()) { + case mtpc_dialog: { + if (const auto peerId = peerFromMTP(dialog.c_dialog().vpeer)) { + if (peerIsChannel(peerId)) { + const auto history = App::history(peerId); + history->applyDialog(dialog.c_dialog()); + channels.push_back(history->peer->asChannel()); + } else { + LOG(("API Error: " + "Unexpected non-channel in feed dialogs list.")); + } + } + } break; + case mtpc_dialogFeed: { + LOG(("API Error: Unexpected dialogFeed in feed dialogs list.")); + } break; + default: Unexpected("Type in DialogsInner::dialogsReceived"); + } + } + + feed->setChannels(channels); + _session->data().sendHistoryChangeNotifications(); +} + void ApiWrap::requestFullPeer(PeerData *peer) { if (!peer || _fullPeerRequests.contains(peer)) return; @@ -1118,12 +1174,12 @@ void ApiWrap::requestSelfParticipant(ChannelData *channel) { case mtpc_channelParticipantSelf: { auto &d = p.vparticipant.c_channelParticipantSelf(); channel->inviter = d.vinviter_id.v; - channel->inviteDate = date(d.vdate); + channel->inviteDate = d.vdate.v; } break; case mtpc_channelParticipantCreator: { auto &d = p.vparticipant.c_channelParticipantCreator(); channel->inviter = _session->userId(); - channel->inviteDate = date(MTP_int(channel->date)); + channel->inviteDate = channel->date; if (channel->mgInfo) { channel->mgInfo->creator = App::self(); } @@ -1131,7 +1187,7 @@ void ApiWrap::requestSelfParticipant(ChannelData *channel) { case mtpc_channelParticipantAdmin: { auto &d = p.vparticipant.c_channelParticipantAdmin(); channel->inviter = d.vinviter_id.v; - channel->inviteDate = date(d.vdate); + channel->inviteDate = d.vdate.v; } break; } @@ -1670,7 +1726,7 @@ void ApiWrap::clearHistory(not_null peer) { if (auto history = App::historyLoaded(peer->id)) { if (const auto last = history->lastMessage()) { deleteTillId = last->id; - Local::addSavedPeer(history->peer, last->date); + Local::addSavedPeer(history->peer, ItemDateTime(last)); } history->clear(); history->newLoaded = history->oldLoaded = true; @@ -2909,8 +2965,10 @@ void ApiWrap::requestFeedChannels(not_null feed) { case mtpc_channels_feedSources: { const auto &data = result.c_channels_feedSources(); - App::feedUsers(data.vusers); - App::feedChats(data.vchats); + + // First we set channels without reading them from data. + // This allows us to apply them all at once without registering + // them one by one. for (const auto &broadcasts : data.vfeeds.v) { if (broadcasts.type() == mtpc_feedBroadcasts) { const auto &list = broadcasts.c_feedBroadcasts(); @@ -2923,6 +2981,10 @@ void ApiWrap::requestFeedChannels(not_null feed) { feed->setChannels(std::move(channels)); } } + + App::feedUsers(data.vusers); + App::feedChats(data.vchats); + if (feed->channelsLoaded()) { feedChannelsDone(feed); } else { @@ -3198,7 +3260,7 @@ void ApiWrap::forwardMessages( history->addNewForwarded( newId.msg, flags, - date(MTP_int(unixtime())), + unixtime(), messageFromId, messagePostAuthor, message); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 91a7f3604..5a7b0f9c4 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -69,6 +69,7 @@ public: void requestContacts(); void requestDialogEntry(not_null feed); + //void requestFeedDialogsEntries(not_null feed); void requestDialogEntry(not_null history); void requestFullPeer(PeerData *peer); @@ -282,6 +283,10 @@ private: QVector collectMessageIds(const MessageDataRequests &requests); MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false); void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs); + void historyDialogEntryApplied(not_null history); + void applyFeedDialogs( + not_null feed, + const MTPmessages_Dialogs &dialogs); void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req); void gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestId req); diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp index cb67cbd8b..c9abc36cc 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.cpp +++ b/Telegram/SourceFiles/boxes/confirm_box.cpp @@ -460,7 +460,7 @@ void DeleteMessagesBox::prepare() { } else { text = _singleItem ? lang(lng_selected_delete_sure_this) : lng_selected_delete_sure(lt_count, _ids.size()); auto canDeleteAllForEveryone = true; - auto now = ::date(unixtime()); + auto now = unixtime(); auto deleteForUser = (UserData*)nullptr; auto peer = (PeerData*)nullptr; auto forEveryoneText = lang(lng_delete_for_everyone_check); @@ -588,7 +588,7 @@ void DeleteMessagesBox::deleteAndClear() { if (wasOnServer) { idsByPeer[history->peer].push_back(MTP_int(itemId.msg)); - } else if (wasLast) { + } else if (wasLast && !history->lastMessageKnown()) { Auth().api().requestDialogEntry(history); } } diff --git a/Telegram/SourceFiles/boxes/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/edit_participant_box.cpp index 7f8323a37..dbb88fe05 100644 --- a/Telegram/SourceFiles/boxes/edit_participant_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_participant_box.cpp @@ -415,7 +415,7 @@ MTPChannelBannedRights EditRestrictedBox::DefaultRights(not_null c void EditRestrictedBox::showRestrictUntil() { auto tomorrow = QDate::currentDate().addDays(1); - auto highlighted = isUntilForever() ? tomorrow : date(getRealUntilValue()).date(); + auto highlighted = isUntilForever() ? tomorrow : ParseDateTime(getRealUntilValue()).date(); auto month = highlighted; _restrictUntilBox = Ui::show( Box( @@ -471,7 +471,11 @@ void EditRestrictedBox::createUntilVariants() { }; auto addCustomVariant = [this, addVariant](TimeId until, TimeId from, TimeId to) { if (!ChannelData::IsRestrictedForever(until) && until > from && until <= to) { - addVariant(until, lng_rights_chat_banned_custom_date(lt_date, langDayOfMonthFull(date(until).date()))); + addVariant( + until, + lng_rights_chat_banned_custom_date( + lt_date, + langDayOfMonthFull(ParseDateTime(until).date()))); } }; auto addCurrentVariant = [this, addCustomVariant](TimeId from, TimeId to) { diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index fc0da2280..a05c8ee74 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -364,15 +364,15 @@ void ContactsBoxController::checkForEmptyRows() { } } -std::unique_ptr ContactsBoxController::createSearchRow(not_null peer) { - if (auto user = peer->asUser()) { +std::unique_ptr ContactsBoxController::createSearchRow( + not_null peer) { + if (const auto user = peer->asUser()) { return createRow(user); } return nullptr; } void ContactsBoxController::rowClicked(not_null row) { - Auth().api().requestDialogEntry(App::history(row->peer())); Ui::showPeerHistory(row->peer(), ShowAtUnreadMsgId); } diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index 539729027..dc1b72658 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -784,7 +784,11 @@ void SingleFilePreview::preparePreview(const Storage::PreparedFile &file) { prepareThumb(preview); const auto filepath = file.path; if (filepath.isEmpty()) { - auto filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true); + auto filename = filedialogDefaultName( + qsl("image"), + qsl(".png"), + QString(), + true); _nameText.setText( st::semiboldTextStyle, filename, diff --git a/Telegram/SourceFiles/boxes/sessions_box.cpp b/Telegram/SourceFiles/boxes/sessions_box.cpp index 946581736..05c9cef13 100644 --- a/Telegram/SourceFiles/boxes/sessions_box.cpp +++ b/Telegram/SourceFiles/boxes/sessions_box.cpp @@ -119,8 +119,9 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) { //CountriesByISO2::const_iterator j = countries.constFind(country); //if (j != countries.cend()) country = QString::fromUtf8(j.value()->name); - MTPint active = d.vdate_active.v ? d.vdate_active : d.vdate_created; - data.activeTime = active.v; + const auto active = data.activeTime = d.vdate_active.v + ? d.vdate_active.v + : d.vdate_created.v; data.info = qs(d.vdevice_model) + qstr(", ") + (platform.isEmpty() ? QString() : platform + ' ') + qs(d.vsystem_version); data.ip = qs(d.vip) + (country.isEmpty() ? QString() : QString::fromUtf8(" \xe2\x80\x93 ") + country); @@ -144,12 +145,15 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) { } _current = data; } else { - QDateTime now(QDateTime::currentDateTime()), lastTime(date(active)); - QDate nowDate(now.date()), lastDate(lastTime.date()); + const auto now = QDateTime::currentDateTime(); + const auto lastTime = ParseDateTime(active); + const auto nowDate = now.date(); + const auto lastDate = lastTime.date(); QString dt; if (lastDate == nowDate) { data.active = lastTime.toString(cTimeFormat()); - } else if (lastDate.year() == nowDate.year() && lastDate.weekNumber() == nowDate.weekNumber()) { + } else if (lastDate.year() == nowDate.year() + && lastDate.weekNumber() == nowDate.weekNumber()) { data.active = langDayOfWeek(lastDate); } else { data.active = lastDate.toString(qsl("d.MM.yy")); diff --git a/Telegram/SourceFiles/calls/calls_box_controller.cpp b/Telegram/SourceFiles/calls/calls_box_controller.cpp index 0e1968954..58b44134f 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.cpp +++ b/Telegram/SourceFiles/calls/calls_box_controller.cpp @@ -39,7 +39,8 @@ public: }; bool canAddItem(not_null item) const { - return (ComputeType(item) == _type && item->date.date() == _date); + return (ComputeType(item) == _type) + && (ItemDateTime(item).date() == _date); } void addItem(not_null item) { Expects(canAddItem(item)); @@ -117,7 +118,7 @@ private: BoxController::Row::Row(not_null item) : PeerListRow(item->history()->peer, item->id) , _items(1, item) -, _date(item->date.date()) +, _date(ItemDateTime(item).date()) , _type(ComputeType(item)) { refreshStatus(); } @@ -162,7 +163,7 @@ void BoxController::Row::refreshStatus() { return; } auto text = [this] { - auto time = _items.front()->date.time().toString(cTimeFormat()); + auto time = ItemDateTime(_items.front()).time().toString(cTimeFormat()); auto today = QDateTime::currentDateTime().date(); if (_date == today) { return lng_call_box_status_today(lt_time, time); diff --git a/Telegram/SourceFiles/core/file_utilities.cpp b/Telegram/SourceFiles/core/file_utilities.cpp index 2adc7729b..fb178a439 100644 --- a/Telegram/SourceFiles/core/file_utilities.cpp +++ b/Telegram/SourceFiles/core/file_utilities.cpp @@ -29,7 +29,7 @@ QString filedialogDefaultName( const QString &extension, const QString &path, bool skipExistance, - int fileTime) { + TimeId fileTime) { auto directoryPath = path; if (directoryPath.isEmpty()) { if (cDialogLastPath().isEmpty()) { @@ -40,7 +40,8 @@ QString filedialogDefaultName( QString base; if (fileTime) { - base = prefix + ::date(fileTime).toString("_yyyy-MM-dd_HH-mm-ss"); + const auto date = ParseDateTime(fileTime); + base = prefix + date.toString("_yyyy-MM-dd_HH-mm-ss"); } else { struct tm tm; time_t t = time(NULL); diff --git a/Telegram/SourceFiles/core/file_utilities.h b/Telegram/SourceFiles/core/file_utilities.h index 70e5fd170..4c180f3ed 100644 --- a/Telegram/SourceFiles/core/file_utilities.h +++ b/Telegram/SourceFiles/core/file_utilities.h @@ -21,7 +21,7 @@ QString filedialogDefaultName( const QString &extension, const QString &path = QString(), bool skipExistance = false, - int fileTime = 0); + TimeId fileTime = TimeId(0)); QString filedialogNextFilename( const QString &name, const QString &cur, diff --git a/Telegram/SourceFiles/core/utils.cpp b/Telegram/SourceFiles/core/utils.cpp index fa2e6c920..c0abc83d7 100644 --- a/Telegram/SourceFiles/core/utils.cpp +++ b/Telegram/SourceFiles/core/utils.cpp @@ -80,7 +80,7 @@ namespace { } } -TimeId myunixtime() { +TimeId LocalUnixtime() { return (TimeId)time(NULL); } @@ -103,31 +103,25 @@ void unixtimeSet(int32 serverTime, bool force) { DEBUG_LOG(("MTP Info: setting client unixtime to %1").arg(serverTime)); } unixtimeWasSet = true; - unixtimeDelta = serverTime + 1 - myunixtime(); + unixtimeDelta = serverTime + 1 - LocalUnixtime(); DEBUG_LOG(("MTP Info: now unixtimeDelta is %1").arg(unixtimeDelta)); } _initMsgIdConstants(); } TimeId unixtime() { - auto result = myunixtime(); + auto result = LocalUnixtime(); QReadLocker locker(&unixtimeLock); return result + unixtimeDelta; } -TimeId fromServerTime(const MTPint &serverTime) { +QDateTime ParseDateTime(TimeId serverTime) { + if (serverTime <= 0) { + return QDateTime(); + } QReadLocker locker(&unixtimeLock); - return serverTime.v - unixtimeDelta; -} - -MTPint toServerTime(const TimeId &clientTime) { - QReadLocker locker(&unixtimeLock); - return MTP_int(clientTime + unixtimeDelta); -} - -QDateTime dateFromServerTime(TimeId time) { - return dateFromServerTime(MTP_int(time)); + return QDateTime::fromTime_t(serverTime - unixtimeDelta); } // Precise timing functions / rand init @@ -224,7 +218,7 @@ namespace { _msgIdCoef = float64(0xFFFF0000L) / 1000000000.; _msStart = 1000LL * static_cast(ts.tv_sec) + (static_cast(ts.tv_nsec) / 1000000LL); #endif - _timeStart = myunixtime(); + _timeStart = LocalUnixtime(); srand((uint32)(_msStart & 0xFFFFFFFFL)); } }; @@ -310,7 +304,7 @@ namespace ThirdParty { } bool checkms() { - auto unixms = (myunixtime() - _timeStart) * 1000LL + _msAddToUnixtime; + auto unixms = (LocalUnixtime() - _timeStart) * 1000LL + _msAddToUnixtime; auto ms = getms(true); if (ms > unixms + 1000LL) { _msAddToUnixtime = ((ms - unixms) / 1000LL) * 1000LL; diff --git a/Telegram/SourceFiles/core/utils.h b/Telegram/SourceFiles/core/utils.h index fc27d5f88..b208db26f 100644 --- a/Telegram/SourceFiles/core/utils.h +++ b/Telegram/SourceFiles/core/utils.h @@ -225,32 +225,14 @@ private: }; -class MTPint; using TimeId = int32; -TimeId myunixtime(); void unixtimeInit(); -void unixtimeSet(TimeId servertime, bool force = false); +void unixtimeSet(TimeId serverTime, bool force = false); TimeId unixtime(); -TimeId fromServerTime(const MTPint &serverTime); -MTPint toServerTime(const TimeId &clientTime); uint64 msgid(); int32 reqid(); -inline QDateTime date(int32 time = -1) { - QDateTime result; - if (time >= 0) result.setTime_t(time); - return result; -} - -inline QDateTime dateFromServerTime(const MTPint &time) { - return date(fromServerTime(time)); -} - -inline QDateTime date(const MTPint &time) { - return dateFromServerTime(time); -} - -QDateTime dateFromServerTime(TimeId time); +QDateTime ParseDateTime(TimeId serverTime); inline void mylocaltime(struct tm * _Tm, const time_t * _Time) { #ifdef Q_OS_WIN diff --git a/Telegram/SourceFiles/data/data_drafts.cpp b/Telegram/SourceFiles/data/data_drafts.cpp index 8c7dd19cd..d5b441552 100644 --- a/Telegram/SourceFiles/data/data_drafts.cpp +++ b/Telegram/SourceFiles/data/data_drafts.cpp @@ -19,11 +19,28 @@ namespace { } // namespace -Draft::Draft(const Ui::FlatTextarea *field, MsgId msgId, bool previewCancelled, mtpRequestId saveRequestId) - : textWithTags(field->getTextWithTags()) - , msgId(msgId) - , cursor(field) - , previewCancelled(previewCancelled) { +Draft::Draft( + const TextWithTags &textWithTags, + MsgId msgId, + const MessageCursor &cursor, + bool previewCancelled, + mtpRequestId saveRequestId) +: textWithTags(textWithTags) +, msgId(msgId) +, cursor(cursor) +, previewCancelled(previewCancelled) +, saveRequestId(saveRequestId) { +} + +Draft::Draft( + not_null field, + MsgId msgId, + bool previewCancelled, + mtpRequestId saveRequestId) +: textWithTags(field->getTextWithTags()) +, msgId(msgId) +, cursor(field) +, previewCancelled(previewCancelled) { } void applyPeerCloudDraft(PeerId peerId, const MTPDdraftMessage &draft) { @@ -32,7 +49,7 @@ void applyPeerCloudDraft(PeerId peerId, const MTPDdraftMessage &draft) { auto textWithTags = TextWithTags { TextUtilities::ApplyEntities(text), ConvertEntitiesToTextTags(text.entities) }; auto replyTo = draft.has_reply_to_msg_id() ? draft.vreply_to_msg_id.v : MsgId(0); auto cloudDraft = std::make_unique(textWithTags, replyTo, MessageCursor(QFIXED_MAX, QFIXED_MAX, QFIXED_MAX), draft.is_no_webpage()); - cloudDraft->date = ::date(draft.vdate); + cloudDraft->date = draft.vdate.v; history->setCloudDraft(std::move(cloudDraft)); history->createLocalDraftFromCloud(); diff --git a/Telegram/SourceFiles/data/data_drafts.h b/Telegram/SourceFiles/data/data_drafts.h index d19b39017..cd3c84d74 100644 --- a/Telegram/SourceFiles/data/data_drafts.h +++ b/Telegram/SourceFiles/data/data_drafts.h @@ -17,18 +17,20 @@ void applyPeerCloudDraft(PeerId peerId, const MTPDdraftMessage &draft); void clearPeerCloudDraft(PeerId peerId); struct Draft { - Draft() { - } - Draft(const TextWithTags &textWithTags, MsgId msgId, const MessageCursor &cursor, bool previewCancelled, mtpRequestId saveRequestId = 0) - : textWithTags(textWithTags) - , msgId(msgId) - , cursor(cursor) - , previewCancelled(previewCancelled) - , saveRequestId(saveRequestId) { - } - Draft(const Ui::FlatTextarea *field, MsgId msgId, bool previewCancelled, mtpRequestId saveRequestId = 0); + Draft() = default; + Draft( + const TextWithTags &textWithTags, + MsgId msgId, + const MessageCursor &cursor, + bool previewCancelled, + mtpRequestId saveRequestId = 0); + Draft( + not_null field, + MsgId msgId, + bool previewCancelled, + mtpRequestId saveRequestId = 0); - QDateTime date; + TimeId date = 0; TextWithTags textWithTags; MsgId msgId = 0; // replyToId for message draft, editMsgId for edit draft MessageCursor cursor; diff --git a/Telegram/SourceFiles/data/data_feed.cpp b/Telegram/SourceFiles/data/data_feed.cpp index 07d927ce2..73617b37c 100644 --- a/Telegram/SourceFiles/data/data_feed.cpp +++ b/Telegram/SourceFiles/data/data_feed.cpp @@ -74,7 +74,7 @@ void Feed::registerOne(not_null channel) { _channels.push_back(history); if (history->lastMessageKnown()) { recountLastMessage(); - } else if (_channelsLoaded) { + } else if (lastMessageKnown()) { _parent->session().api().requestDialogEntry(history); } _parent->session().storage().remove( @@ -121,7 +121,7 @@ void Feed::unregisterOne(not_null channel) { void Feed::updateLastMessage(not_null item) { if (justUpdateLastMessage(item)) { if (_lastMessage && *_lastMessage) { - setChatsListDate((*_lastMessage)->date); + setChatsListDate(ItemDateTime(*_lastMessage)); } } } @@ -192,15 +192,22 @@ void Feed::setChannels(std::vector> channels) { _channels, channel.get(), [](auto history) { return history->peer->asChannel(); } - ) != end(_channels); + ) == end(_channels); }) | ranges::to_vector; for (const auto channel : remove) { channel->clearFeed(); } + + // We assume the last message was correct before requesting the list. + // So we save it and don't allow channels from the list to change it. + // After that we restore it. + const auto oldLastMessage = base::take(_lastMessage); for (const auto channel : add) { + _lastMessage = base::none; channel->setFeed(this); } + _lastMessage = oldLastMessage; _channels.clear(); for (const auto channel : channels) { @@ -256,7 +263,7 @@ void Feed::recountLastMessage() { void Feed::updateChatsListDate() { if (_lastMessage && *_lastMessage) { - setChatsListDate((*_lastMessage)->date); + setChatsListDate(ItemDateTime(*_lastMessage)); } } @@ -268,6 +275,14 @@ bool Feed::lastMessageKnown() const { return !!_lastMessage; } +int Feed::unreadCount() const { + return _unreadCount ? *_unreadCount : 0; +} + +bool Feed::unreadCountKnown() const { + return !!_unreadCount; +} + void Feed::applyDialog(const MTPDdialogFeed &data) { const auto addChannel = [&](ChannelId channelId) { if (const auto channel = App::channelLoaded(channelId)) { @@ -299,8 +314,14 @@ void Feed::applyDialog(const MTPDdialogFeed &data) { } void Feed::setUnreadCounts(int unreadNonMutedCount, int unreadMutedCount) { + if (unreadCountKnown() + && (*_unreadCount == unreadNonMutedCount + unreadMutedCount) + && (_unreadMutedCount == unreadMutedCount)) { + return; + } _unreadCount = unreadNonMutedCount + unreadMutedCount; _unreadMutedCount = unreadMutedCount; + updateChatListEntry(); } void Feed::setUnreadPosition(const MessagePosition &position) { @@ -312,7 +333,7 @@ void Feed::setUnreadPosition(const MessagePosition &position) { void Feed::unreadCountChanged( base::optional unreadCountDelta, int mutedCountDelta) { - if (!_unreadCount) { + if (!unreadCountKnown()) { return; } if (unreadCountDelta) { @@ -323,6 +344,9 @@ void Feed::unreadCountChanged( *_unreadCount); updateChatListEntry(); } else { +// _parent->session().api().requestFeedDialogsEntries(this); + // Happens once for each channel with unknown unread count. + // Requesting all feed dialogs could be huge and even have slicing. _parent->session().api().requestDialogEntry(this); } } @@ -344,7 +368,7 @@ bool Feed::shouldBeInChatList() const { } int Feed::chatListUnreadCount() const { - return _unreadCount ? *_unreadCount : 0; + return unreadCount(); } bool Feed::chatListMutedBadge() const { diff --git a/Telegram/SourceFiles/data/data_feed.h b/Telegram/SourceFiles/data/data_feed.h index 708001e87..74217d2e9 100644 --- a/Telegram/SourceFiles/data/data_feed.h +++ b/Telegram/SourceFiles/data/data_feed.h @@ -55,6 +55,8 @@ public: HistoryItem *lastMessage() const; bool lastMessageKnown() const; + int unreadCount() const; + bool unreadCountKnown() const; bool toImportant() const override; bool shouldBeInChatList() const override; diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index c8bc7ea65..d1790c61b 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -946,8 +946,8 @@ public: || amCreator(); } - int32 inviter = 0; // > 0 - user who invited me to channel, < 0 - not in channel - QDateTime inviteDate; + UserId inviter = 0; // > 0 - user who invited me to channel, < 0 - not in channel + TimeId inviteDate = 0; void ptsInit(int32 pts) { _ptsWaiter.init(pts); diff --git a/Telegram/SourceFiles/data/data_peer_values.cpp b/Telegram/SourceFiles/data/data_peer_values.cpp index 5c5533966..8d55136e4 100644 --- a/Telegram/SourceFiles/data/data_peer_values.cpp +++ b/Telegram/SourceFiles/data/data_peer_values.cpp @@ -14,6 +14,7 @@ namespace { constexpr auto kMinOnlineChangeTimeout = TimeMs(1000); constexpr auto kMaxOnlineChangeTimeout = 86400 * TimeMs(1000); +constexpr auto kSecondsInDay = 86400; int OnlinePhraseChangeInSeconds(TimeId online, TimeId now) { if (online <= 0) { @@ -33,7 +34,7 @@ int OnlinePhraseChangeInSeconds(TimeId online, TimeId now) { if (hours < 12) { return (hours + 1) * 3600 - (now - online); } - const auto nowFull = ::date(now); + const auto nowFull = ParseDateTime(now); const auto tomorrow = QDateTime(nowFull.date().addDays(1)); return static_cast(nowFull.secsTo(tomorrow)); } @@ -175,27 +176,21 @@ TimeId SortByOnlineValue(not_null user, TimeId now) { return -1; } const auto online = user->onlineTill; - const auto fromDate = [](const QDate &date) { - return toServerTime(QDateTime(date).toTime_t()).v; - }; if (online <= 0) { switch (online) { case 0: case -1: return online; case -2: { - const auto recently = date(now).date().addDays(-3); - return fromDate(recently); + return now - 3 * kSecondsInDay; } break; case -3: { - const auto weekago = date(now).date().addDays(-7); - return fromDate(weekago); + return now - 7 * kSecondsInDay; } break; case -4: { - const auto monthago = date(now).date().addDays(-30); - return fromDate(monthago); + return now - 30 * kSecondsInDay; } break; } return -online; @@ -233,8 +228,8 @@ QString OnlineText(TimeId online, TimeId now) { if (hours < 12) { return lng_status_lastseen_hours(lt_count, hours); } - const auto onlineFull = ::date(online); - const auto nowFull = ::date(now); + const auto onlineFull = ParseDateTime(online); + const auto nowFull = ParseDateTime(now); if (onlineFull.date() == nowFull.date()) { const auto onlineTime = onlineFull.time().toString(cTimeFormat()); return lng_status_lastseen_today(lt_time, onlineTime); @@ -259,8 +254,8 @@ QString OnlineTextFull(not_null user, TimeId now) { } else if (const auto common = OnlineTextCommon(user->onlineTill, now)) { return *common; } - const auto onlineFull = ::date(user->onlineTill); - const auto nowFull = ::date(now); + const auto onlineFull = ParseDateTime(user->onlineTill); + const auto nowFull = ParseDateTime(now); if (onlineFull.date() == nowFull.date()) { const auto onlineTime = onlineFull.time().toString(cTimeFormat()); return lng_status_lastseen_today(lt_time, onlineTime); diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp index 346454b60..baa59f8bc 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp @@ -32,22 +32,6 @@ uint64 PinnedDialogPos(int pinnedIndex) { } // namespace -bool MessageIsLess(not_null a, not_null b) { - if (a->date < b->date) { - return true; - } else if (b->date < a->date) { - return false; - } - const auto apeer = a->history()->peer->bareId(); - const auto bpeer = b->history()->peer->bareId(); - if (apeer < bpeer) { - return true; - } else if (bpeer < apeer) { - return false; - } - return a->id < b->id; -} - Entry::Entry(const Key &key) : lastItemTextCache(st::dialogsTextWidthMin) , _key(key) { @@ -127,7 +111,7 @@ PositionChange Entry::adjustByPosInChatList( return { movedFrom, movedTo }; } -void Entry::setChatsListDate(const QDateTime &date) { +void Entry::setChatsListDate(QDateTime date) { if (!_lastMessageDate.isNull() && _lastMessageDate >= date) { if (!inChatList(Dialogs::Mode::All)) { return; diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.h b/Telegram/SourceFiles/dialogs/dialogs_entry.h index 96d5f3a8b..a30712efe 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_entry.h +++ b/Telegram/SourceFiles/dialogs/dialogs_entry.h @@ -33,8 +33,6 @@ struct PositionChange { int movedTo; }; -bool MessageIsLess(not_null a, not_null b); - class Entry { public: Entry(const Key &key); @@ -62,7 +60,7 @@ public: return _sortKeyInChatList; } void updateChatListSortPosition(); - void setChatsListDate(const QDateTime &date); + void setChatsListDate(QDateTime date); virtual void updateChatListExistence(); bool needUpdateInChatList() const; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 9793f21d8..16a6fbd49 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -1716,7 +1716,6 @@ void DialogsInner::dialogsReceived(const QVector &added) { default: Unexpected("Type in DialogsInner::dialogsReceived"); } } - Notify::unreadCounterUpdated(); refresh(); } @@ -1729,8 +1728,11 @@ void DialogsInner::applyDialog(const MTPDdialog &dialog) { const auto history = App::history(peerId); history->applyDialog(dialog); - if (!history->isPinnedDialog() && !history->chatsListDate().isNull()) { - addSavedPeersAfter(history->chatsListDate()); + if (!history->isPinnedDialog()) { + const auto date = history->chatsListDate(); + if (!date.isNull()) { + addSavedPeersAfter(date); + } } _contactsNoDialogs->del(history); if (const auto from = history->peer->migrateFrom()) { @@ -1749,8 +1751,11 @@ void DialogsInner::applyFeedDialog(const MTPDdialogFeed &dialog) { const auto feed = Auth().data().feed(feedId); feed->applyDialog(dialog); - if (!feed->isPinnedDialog() && !feed->chatsListDate().isNull()) { - addSavedPeersAfter(feed->chatsListDate()); + if (!feed->isPinnedDialog()) { + const auto date = feed->chatsListDate(); + if (!date.isNull()) { + addSavedPeersAfter(date); + } } } diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 6055a7931..5e2125aea 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -25,7 +25,7 @@ namespace { // Show all dates that are in the last 20 hours in time format. constexpr int kRecentlyInSeconds = 20 * 3600; -void paintRowDate(Painter &p, const QDateTime &date, QRect &rectForName, bool active, bool selected) { +void paintRowDate(Painter &p, QDateTime date, QRect &rectForName, bool active, bool selected) { auto now = QDateTime::currentDateTime(); auto lastTime = date; auto nowDate = now.date(); @@ -389,13 +389,13 @@ void RowPainter::paint( const auto displayDate = [item, cloudDraft] { if (item) { if (cloudDraft) { - return (item->date > cloudDraft->date) - ? item->date - : cloudDraft->date; + return (item->date() > cloudDraft->date) + ? ItemDateTime(item) + : ParseDateTime(cloudDraft->date); } - return item->date; + return ItemDateTime(item); } - return cloudDraft ? cloudDraft->date : QDateTime(); + return cloudDraft ? ParseDateTime(cloudDraft->date) : QDateTime(); }(); const auto from = history @@ -581,7 +581,7 @@ void RowPainter::paint( from, item, cloudDraft, - item->date, + ItemDateTime(item), fullWidth, flags, ms, diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index 52fb6c7f4..d5a4b59c7 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -455,7 +455,7 @@ QString InnerWidget::tooltipText() const { if (_mouseCursorState == CursorState::Date && _mouseAction == MouseAction::None) { if (const auto view = App::hoveredItem()) { - auto dateText = view->data()->date.toString( + auto dateText = view->dateTime().toString( QLocale::system().dateTimeFormat(QLocale::LongFormat)); return dateText; } @@ -666,7 +666,7 @@ void InnerWidget::itemsAdded(Direction direction, int addedCount) { const auto view = _items[i - 1].get(); if (i < _items.size()) { const auto previous = _items[i].get(); - view->setDisplayDate(view->data()->date.date() != previous->data()->date.date()); + view->setDisplayDate(view->dateTime().date() != previous->dateTime().date()); const auto attach = view->computeIsAttachToPrevious(previous); view->setAttachToPrevious(attach); previous->setAttachToNext(attach); @@ -796,7 +796,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { } else { HistoryView::ServiceMessagePainter::paintDate( p, - view->data()->date, + view->dateTime(), dateY, width); } diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp index 861607303..783ab111e 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp @@ -105,7 +105,7 @@ TextWithEntities ExtractEditedText(const MTPMessage &message) { return { text, entities }; } -PhotoData *GenerateChatPhoto(ChannelId channelId, uint64 logEntryId, MTPint date, const MTPDchatPhoto &photo) { +PhotoData *GenerateChatPhoto(ChannelId channelId, uint64 logEntryId, TimeId date, const MTPDchatPhoto &photo) { // We try to make a unique photoId that will stay the same for each pair (channelId, logEntryId). static const auto RandomIdPart = rand_value(); auto mixinIdPart = (static_cast(static_cast(channelId)) << 32) ^ logEntryId; @@ -119,7 +119,7 @@ PhotoData *GenerateChatPhoto(ChannelId channelId, uint64 logEntryId, MTPint date MTP_flags(0), MTP_long(photoId), MTP_long(0), - date, + MTP_int(date), MTP_vector(photoSizes))); } @@ -184,13 +184,21 @@ auto GenerateBannedChangeText(const TextWithEntities &user, const MTPChannelBann Expects(!prevRights || prevRights->type() == mtpc_channelBannedRights); auto newFlags = newRights ? newRights->c_channelBannedRights().vflags.v : MTPDchannelBannedRights::Flags(0); auto prevFlags = prevRights ? prevRights->c_channelBannedRights().vflags.v : MTPDchannelBannedRights::Flags(0); - auto newUntil = newRights ? newRights->c_channelBannedRights().vuntil_date : MTP_int(0); - auto indefinitely = ChannelData::IsRestrictedForever(newUntil.v); + auto newUntil = newRights ? newRights->c_channelBannedRights().vuntil_date.v : TimeId(0); + auto indefinitely = ChannelData::IsRestrictedForever(newUntil); if (newFlags & Flag::f_view_messages) { return lng_admin_log_banned__generic(lt_user, user); } - auto untilText = indefinitely ? lang(lng_admin_log_restricted_forever) : lng_admin_log_restricted_until(lt_date, langDateTime(::date(newUntil))); - auto result = lng_admin_log_restricted__generic(lt_user, user, lt_until, TextWithEntities { untilText }); + auto untilText = indefinitely + ? lang(lng_admin_log_restricted_forever) + : lng_admin_log_restricted_until( + lt_date, + langDateTime(ParseDateTime(newUntil))); + auto result = lng_admin_log_restricted__generic( + lt_user, + user, + lt_until, + TextWithEntities { untilText }); static auto phraseMap = std::map { { Flag::f_view_messages, lng_admin_log_banned_view_messages }, @@ -321,7 +329,7 @@ void GenerateItems( auto from = App::user(event.vuser_id.v); auto channel = history->peer->asChannel(); auto &action = event.vaction; - auto date = event.vdate; + auto date = event.vdate.v; auto addPart = [&](not_null item) { return callback(OwnedItem(delegate, item)); }; @@ -334,7 +342,7 @@ void GenerateItems( auto addSimpleServiceMessage = [&](const QString &text, PhotoData *photo = nullptr) { auto message = HistoryService::PreparedText { text }; message.links.push_back(fromLink); - addPart(new HistoryService(history, idManager->next(), ::date(date), message, 0, peerToUser(from->id), photo)); + addPart(new HistoryService(history, idManager->next(), date, message, 0, peerToUser(from->id), photo)); }; auto createChangeTitle = [&](const MTPDchannelAdminLogEventActionChangeTitle &action) { @@ -355,7 +363,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto newDescription = PrepareText(newValue, QString()); - auto body = new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(from->id), QString(), newDescription); + auto body = new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), newDescription); if (!oldValue.isEmpty()) { auto oldDescription = PrepareText(oldValue, QString()); body->addLogEntryOriginal(id, lang(lng_admin_log_previous_description), oldDescription); @@ -376,7 +384,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto newLink = newValue.isEmpty() ? TextWithEntities() : PrepareText(Messenger::Instance().createInternalLinkFull(newValue), QString()); - auto body = new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(from->id), QString(), newLink); + auto body = new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), newLink); if (!oldValue.isEmpty()) { auto oldLink = PrepareText(Messenger::Instance().createInternalLinkFull(oldValue), QString()); body->addLogEntryOriginal(id, lang(lng_admin_log_previous_link), oldLink); @@ -428,7 +436,7 @@ void GenerateItems( PrepareLogMessage( action.vmessage, idManager->next(), - date.v), + date), detachExistingItem)); } }; @@ -448,7 +456,7 @@ void GenerateItems( PrepareLogMessage( action.vnew_message, idManager->next(), - date.v), + date), detachExistingItem); if (oldValue.text.isEmpty()) { oldValue = PrepareText(QString(), lang(lng_admin_log_empty_text)); @@ -463,7 +471,7 @@ void GenerateItems( auto detachExistingItem = false; addPart(history->createItem( - PrepareLogMessage(action.vmessage, idManager->next(), date.v), + PrepareLogMessage(action.vmessage, idManager->next(), date), detachExistingItem)); }; @@ -486,7 +494,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto bodyText = GenerateParticipantChangeText(channel, action.vparticipant); - addPart(new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(from->id), QString(), bodyText)); + addPart(new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), bodyText)); }; auto createParticipantToggleBan = [&](const MTPDchannelAdminLogEventActionParticipantToggleBan &action) { @@ -494,7 +502,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant, &action.vprev_participant); - addPart(new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(from->id), QString(), bodyText)); + addPart(new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), bodyText)); }; auto createParticipantToggleAdmin = [&](const MTPDchannelAdminLogEventActionParticipantToggleAdmin &action) { @@ -502,7 +510,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant, &action.vprev_participant); - addPart(new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(from->id), QString(), bodyText)); + addPart(new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), bodyText)); }; auto createChangeStickerSet = [&](const MTPDchannelAdminLogEventActionChangeStickerSet &action) { @@ -523,7 +531,7 @@ void GenerateItems( auto message = HistoryService::PreparedText { text }; message.links.push_back(fromLink); message.links.push_back(setLink); - addPart(new HistoryService(history, idManager->next(), ::date(date), message, 0, peerToUser(from->id))); + addPart(new HistoryService(history, idManager->next(), date, message, 0, peerToUser(from->id))); } }; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index cbfdf31f7..fe44e92e4 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -322,12 +322,18 @@ void History::takeLocalDraft(History *from) { void History::createLocalDraftFromCloud() { auto draft = cloudDraft(); - if (Data::draftIsNull(draft) || !draft->date.isValid()) return; + if (Data::draftIsNull(draft) || !draft->date) { + return; + } auto existing = localDraft(); - if (Data::draftIsNull(existing) || !existing->date.isValid() || draft->date >= existing->date) { + if (Data::draftIsNull(existing) || !existing->date || draft->date >= existing->date) { if (!existing) { - setLocalDraft(std::make_unique(draft->textWithTags, draft->msgId, draft->cursor, draft->previewCancelled)); + setLocalDraft(std::make_unique( + draft->textWithTags, + draft->msgId, + draft->cursor, + draft->previewCancelled)); existing = localDraft(); } else if (existing != draft) { existing->textWithTags = draft->textWithTags; @@ -351,11 +357,15 @@ Data::Draft *History::createCloudDraft(Data::Draft *fromDraft) { 0, MessageCursor(), false)); - cloudDraft()->date = QDateTime(); + cloudDraft()->date = TimeId(0); } else { auto existing = cloudDraft(); if (!existing) { - setCloudDraft(std::make_unique(fromDraft->textWithTags, fromDraft->msgId, fromDraft->cursor, fromDraft->previewCancelled)); + setCloudDraft(std::make_unique( + fromDraft->textWithTags, + fromDraft->msgId, + fromDraft->cursor, + fromDraft->previewCancelled)); existing = cloudDraft(); } else if (existing != fromDraft) { existing->textWithTags = fromDraft->textWithTags; @@ -363,7 +373,7 @@ Data::Draft *History::createCloudDraft(Data::Draft *fromDraft) { existing->cursor = fromDraft->cursor; existing->previewCancelled = fromDraft->previewCancelled; } - existing->date = ::date(myunixtime()); + existing->date = unixtime(); } cloudDraftTextCache.clear(); @@ -623,99 +633,9 @@ std::vector> History::createItems( return result; } -not_null History::createItemForwarded( - MsgId id, - MTPDmessage::Flags flags, - QDateTime date, - UserId from, - const QString &postAuthor, - HistoryMessage *original) { - return new HistoryMessage( - this, - id, - flags, - date, - from, - postAuthor, - original); -} - -not_null History::createItemDocument( - MsgId id, - MTPDmessage::Flags flags, - UserId viaBotId, - MsgId replyTo, - QDateTime date, - UserId from, - const QString &postAuthor, - DocumentData *document, - const TextWithEntities &caption, - const MTPReplyMarkup &markup) { - return new HistoryMessage( - this, - id, - flags, - replyTo, - viaBotId, - date, - from, - postAuthor, - document, - caption, - markup); -} - -not_null History::createItemPhoto( - MsgId id, - MTPDmessage::Flags flags, - UserId viaBotId, - MsgId replyTo, - QDateTime date, - UserId from, - const QString &postAuthor, - PhotoData *photo, - const TextWithEntities &caption, - const MTPReplyMarkup &markup) { - return new HistoryMessage( - this, - id, - flags, - replyTo, - viaBotId, - date, - from, - postAuthor, - photo, - caption, - markup); -} - -not_null History::createItemGame( - MsgId id, - MTPDmessage::Flags flags, - UserId viaBotId, - MsgId replyTo, - QDateTime date, - UserId from, - const QString &postAuthor, - GameData *game, - const MTPReplyMarkup &markup) { - return new HistoryMessage( - this, - id, - flags, - replyTo, - viaBotId, - date, - from, - postAuthor, - game, - markup); -} - not_null History::addNewService( MsgId msgId, - QDateTime date, + TimeId date, const QString &text, MTPDmessage::Flags flags, bool unread) { @@ -781,12 +701,19 @@ HistoryItem *History::addToHistory(const MTPMessage &msg) { not_null History::addNewForwarded( MsgId id, MTPDmessage::Flags flags, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, - HistoryMessage *original) { + not_null original) { return addNewItem( - createItemForwarded(id, flags, date, from, postAuthor, original), + new HistoryMessage( + this, + id, + flags, + date, + from, + postAuthor, + original), true); } @@ -795,18 +722,19 @@ not_null History::addNewDocument( MTPDmessage::Flags flags, UserId viaBotId, MsgId replyTo, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, - DocumentData *document, + not_null document, const TextWithEntities &caption, const MTPReplyMarkup &markup) { return addNewItem( - createItemDocument( + new HistoryMessage( + this, id, flags, - viaBotId, replyTo, + viaBotId, date, from, postAuthor, @@ -821,18 +749,19 @@ not_null History::addNewPhoto( MTPDmessage::Flags flags, UserId viaBotId, MsgId replyTo, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, - PhotoData *photo, + not_null photo, const TextWithEntities &caption, const MTPReplyMarkup &markup) { return addNewItem( - createItemPhoto( + new HistoryMessage( + this, id, flags, - viaBotId, replyTo, + viaBotId, date, from, postAuthor, @@ -847,17 +776,18 @@ not_null History::addNewGame( MTPDmessage::Flags flags, UserId viaBotId, MsgId replyTo, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, - GameData *game, + not_null game, const MTPReplyMarkup &markup) { return addNewItem( - createItemGame( + new HistoryMessage( + this, id, flags, - viaBotId, replyTo, + viaBotId, date, from, postAuthor, @@ -1291,8 +1221,7 @@ void History::newItemAdded(not_null item) { if (from == item->author()) { clearSendAction(from); } - auto itemServerTime = toServerTime(item->date.toTime_t()); - from->madeAction(itemServerTime.v); + from->madeAction(item->date()); } if (item->out()) { destroyUnreadBar(); @@ -1670,6 +1599,10 @@ int History::unreadCount() const { return _unreadCount ? *_unreadCount : 0; } +bool History::unreadCountKnown() const { + return !!_unreadCount; +} + void History::setUnreadCount(int newUnreadCount) { if (!_unreadCount || *_unreadCount != newUnreadCount) { const auto unreadCountDelta = _unreadCount | [&](int count) { @@ -1805,8 +1738,11 @@ std::shared_ptr History::adminLogIdManager() { QDateTime History::adjustChatListDate() const { const auto result = chatsListDate(); if (const auto draft = cloudDraft()) { - if (!Data::draftIsNull(draft) && draft->date > result) { - return draft->date; + if (!Data::draftIsNull(draft)) { + const auto draftResult = ParseDateTime(draft->date); + if (draftResult > result) { + return draftResult; + } } } return result; @@ -2123,7 +2059,7 @@ void History::setLastMessage(HistoryItem *item) { if (const auto feed = peer->feed()) { feed->updateLastMessage(item); } - setChatsListDate(item->date); + setChatsListDate(ItemDateTime(item)); } else if (!_lastMessage || *_lastMessage) { _lastMessage = nullptr; updateChatListEntry(); @@ -2140,7 +2076,7 @@ bool History::lastMessageKnown() const { void History::updateChatListExistence() { Entry::updateChatListExistence(); - if (!lastMessageKnown() || !_unreadCount) { + if (!lastMessageKnown() || !unreadCountKnown()) { if (const auto channel = peer->asChannel()) { if (!channel->feed()) { // After ungrouping from a feed we need to load dialog. @@ -2197,7 +2133,7 @@ void History::applyDialog(const MTPDdialog &data) { peerToChannel(channel->id), data.vtop_message.v); if (const auto item = App::histItemById(topMessageId)) { - if (item->date <= date(channel->date)) { + if (item->date() <= channel->date) { Auth().api().requestSelfParticipant(channel); } } @@ -2384,7 +2320,7 @@ HistoryService *History::insertJoinedMessage(bool unread) { // flags |= MTPDmessage::Flag::f_unread; } - auto inviteDate = peer->asChannel()->inviteDate; + const auto inviteDate = peer->asChannel()->inviteDate; if (isEmpty()) { _joinedMessage = GenerateJoinedMessage( this, @@ -2409,7 +2345,7 @@ HistoryService *History::insertJoinedMessage(bool unread) { peer->asChannel()->mgInfo->joinedMessageFound = true; return nullptr; } - if (item->date <= inviteDate) { + if (item->date() <= inviteDate) { ++itemIndex; _joinedMessage = GenerateJoinedMessage( this, @@ -2418,7 +2354,7 @@ HistoryService *History::insertJoinedMessage(bool unread) { flags); addNewInTheMiddle(_joinedMessage, blockIndex, itemIndex); const auto lastDate = chatsListDate(); - if (lastDate.isNull() || inviteDate >= lastDate) { + if (lastDate.isNull() || ParseDateTime(inviteDate) >= lastDate) { setLastMessage(_joinedMessage); if (unread) { newItemAdded(_joinedMessage); @@ -2456,14 +2392,15 @@ void History::checkJoinedMessage(bool createUnread) { } } - QDateTime inviteDate = peer->asChannel()->inviteDate; - QDateTime firstDate, lastDate; + const auto inviteDate = peer->asChannel()->inviteDate; + auto firstDate = TimeId(0); + auto lastDate = TimeId(0); if (!blocks.empty()) { - firstDate = blocks.front()->messages.front()->data()->date; - lastDate = blocks.back()->messages.back()->data()->date; + firstDate = blocks.front()->messages.front()->data()->date(); + lastDate = blocks.back()->messages.back()->data()->date(); } - if (!firstDate.isNull() - && !lastDate.isNull() + if (firstDate + && lastDate && (firstDate <= inviteDate || loadedAtTop()) && (lastDate > inviteDate || loadedAtBottom())) { const auto willBeLastMsg = (inviteDate >= lastDate); @@ -2596,7 +2533,7 @@ void History::clearUpTill(MsgId availableMinId) { MTP_int(fromId), peerToMTP(peer->id), MTP_int(replyToId), - toServerTime(item->date.toTime_t()), + MTP_int(item->date()), MTP_messageActionHistoryClear() ).c_messageService()); } diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 5b9c8b773..fd3351992 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -148,15 +148,56 @@ public: void unloadBlocks(); void clearUpTill(MsgId availableMinId); - void applyGroupAdminChanges(const base::flat_map &changes); + void applyGroupAdminChanges( + const base::flat_map &changes); HistoryItem *addNewMessage(const MTPMessage &msg, NewMessageType type); HistoryItem *addToHistory(const MTPMessage &msg); - not_null addNewService(MsgId msgId, QDateTime date, const QString &text, MTPDmessage::Flags flags = 0, bool newMsg = true); - not_null addNewForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, UserId from, const QString &postAuthor, HistoryMessage *item); - not_null addNewDocument(MsgId id, MTPDmessage::Flags flags, UserId viaBotId, MsgId replyTo, QDateTime date, UserId from, const QString &postAuthor, DocumentData *doc, const TextWithEntities &caption, const MTPReplyMarkup &markup); - not_null addNewPhoto(MsgId id, MTPDmessage::Flags flags, UserId viaBotId, MsgId replyTo, QDateTime date, UserId from, const QString &postAuthor, PhotoData *photo, const TextWithEntities &caption, const MTPReplyMarkup &markup); - not_null addNewGame(MsgId id, MTPDmessage::Flags flags, UserId viaBotId, MsgId replyTo, QDateTime date, UserId from, const QString &postAuthor, GameData *game, const MTPReplyMarkup &markup); + not_null addNewService( + MsgId msgId, + TimeId date, + const QString &text, + MTPDmessage::Flags flags = 0, + bool newMsg = true); + not_null addNewForwarded( + MsgId id, + MTPDmessage::Flags flags, + TimeId date, + UserId from, + const QString &postAuthor, + not_null original); + not_null addNewDocument( + MsgId id, + MTPDmessage::Flags flags, + UserId viaBotId, + MsgId replyTo, + TimeId date, + UserId from, + const QString &postAuthor, + not_null document, + const TextWithEntities &caption, + const MTPReplyMarkup &markup); + not_null addNewPhoto( + MsgId id, + MTPDmessage::Flags flags, + UserId viaBotId, + MsgId replyTo, + TimeId date, + UserId from, + const QString &postAuthor, + not_null photo, + const TextWithEntities &caption, + const MTPReplyMarkup &markup); + not_null addNewGame( + MsgId id, + MTPDmessage::Flags flags, + UserId viaBotId, + MsgId replyTo, + TimeId date, + UserId from, + const QString &postAuthor, + not_null game, + const MTPReplyMarkup &markup); // Used only internally and for channel admin log. HistoryItem *createItem( @@ -180,6 +221,7 @@ public: MsgId loadAroundId() const; int unreadCount() const; + bool unreadCountKnown() const; void setUnreadCount(int newUnreadCount); bool mute() const; bool changeMute(bool newMute); @@ -376,11 +418,6 @@ private: void clearBlocks(bool leaveItems); - not_null createItemForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, UserId from, const QString &postAuthor, HistoryMessage *msg); - not_null createItemDocument(MsgId id, MTPDmessage::Flags flags, UserId viaBotId, MsgId replyTo, QDateTime date, UserId from, const QString &postAuthor, DocumentData *doc, const TextWithEntities &caption, const MTPReplyMarkup &markup); - not_null createItemPhoto(MsgId id, MTPDmessage::Flags flags, UserId viaBotId, MsgId replyTo, QDateTime date, UserId from, const QString &postAuthor, PhotoData *photo, const TextWithEntities &caption, const MTPReplyMarkup &markup); - not_null createItemGame(MsgId id, MTPDmessage::Flags flags, UserId viaBotId, MsgId replyTo, QDateTime date, UserId from, const QString &postAuthor, GameData *game, const MTPReplyMarkup &markup); - not_null addNewItem( not_null item, bool unread); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 904221467..bb5fc6c9a 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -731,7 +731,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { } else { HistoryView::ServiceMessagePainter::paintDate( p, - view->data()->date, + view->dateTime(), dateY, _contentWidth); } @@ -1430,7 +1430,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { _widget->replyToMessage(itemId); }); } - if (item->allowsEdit(::date(unixtime()))) { + if (item->allowsEdit(unixtime())) { _menu->addAction(lang(lng_context_edit_msg), [=] { _widget->editMessage(itemId); }); @@ -1693,11 +1693,17 @@ void HistoryInner::savePhotoToFile(not_null photo) { if (!photo->date || !photo->loaded()) return; auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter(); - FileDialog::GetWritePath(lang(lng_save_photo), filter, filedialogDefaultName(qsl("photo"), qsl(".jpg")), base::lambda_guarded(this, [this, photo](const QString &result) { - if (!result.isEmpty()) { - photo->full->pix().toImage().save(result, "JPG"); - } - })); + FileDialog::GetWritePath( + lang(lng_save_photo), + filter, + filedialogDefaultName( + qsl("photo"), + qsl(".jpg")), + base::lambda_guarded(this, [this, photo](const QString &result) { + if (!result.isEmpty()) { + photo->full->pix().toImage().save(result, "JPG"); + } + })); } void HistoryInner::copyContextImage(not_null photo) { @@ -1797,7 +1803,7 @@ TextWithEntities HistoryInner::getSelectedText() const { const auto wrapItem = [&]( not_null item, TextWithEntities &&unwrapped) { - auto time = item->date.toString(timeFormat); + auto time = ItemDateTime(item).toString(timeFormat); auto part = TextWithEntities(); auto size = item->author()->name.size() + time.size() @@ -1886,7 +1892,7 @@ void HistoryInner::recountHistoryGeometry() { _historySkipHeight = 0; if (_migrated) { if (!_migrated->isEmpty() && !_history->isEmpty() && _migrated->loadedAtBottom() && _history->loadedAtTop()) { - if (_migrated->blocks.back()->messages.back()->data()->date.date() == _history->blocks.front()->messages.front()->data()->date.date()) { + if (_migrated->blocks.back()->messages.back()->dateTime().date() == _history->blocks.front()->messages.front()->dateTime().date()) { if (_migrated->blocks.back()->messages.back()->data()->isGroupMigrate() && _history->blocks.front()->messages.front()->data()->isGroupMigrate()) { _historySkipHeight += _history->blocks.front()->messages.front()->height(); } else { @@ -2379,7 +2385,7 @@ void HistoryInner::mouseActionUpdate() { if (const auto date = view->Get()) { dateWidth = date->width; } else { - dateWidth = st::msgServiceFont->width(langDayOfMonthFull(item->date.date())); + dateWidth = st::msgServiceFont->width(langDayOfMonthFull(view->dateTime().date())); } dateWidth += st::msgServicePadding.left() + st::msgServicePadding.right(); auto dateLeft = st::msgServiceMargin.left(); @@ -2393,9 +2399,9 @@ void HistoryInner::mouseActionUpdate() { if (point.x() >= dateLeft && point.x() < dateLeft + dateWidth) { if (!_scrollDateLink) { - _scrollDateLink = std::make_shared(item->history()->peer, item->date.date()); + _scrollDateLink = std::make_shared(item->history()->peer, view->dateTime().date()); } else { - static_cast(_scrollDateLink.get())->setDate(item->date.date()); + static_cast(_scrollDateLink.get())->setDate(view->dateTime().date()); } dragState = TextState( nullptr, @@ -2924,14 +2930,21 @@ QString HistoryInner::tooltipText() const { if (_mouseCursorState == CursorState::Date && _mouseAction == MouseAction::None) { if (const auto view = App::hoveredItem()) { - auto dateText = view->data()->date.toString( + auto dateText = view->dateTime().toString( QLocale::system().dateTimeFormat(QLocale::LongFormat)); - auto editedDate = view->displayedEditDate(); - if (!editedDate.isNull()) { - dateText += '\n' + lng_edited_date(lt_date, editedDate.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat))); + if (const auto editedDate = view->displayedEditDate()) { + dateText += '\n' + lng_edited_date( + lt_date, + ParseDateTime(editedDate).toString( + QLocale::system().dateTimeFormat( + QLocale::LongFormat))); } if (const auto forwarded = view->data()->Get()) { - dateText += '\n' + lng_forwarded_date(lt_date, forwarded->originalDate.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat))); + dateText += '\n' + lng_forwarded_date( + lt_date, + ParseDateTime(forwarded->originalDate).toString( + QLocale::system().dateTimeFormat( + QLocale::LongFormat))); } return dateText; } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 3a5e946d8..231dfb0af 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -47,7 +47,7 @@ not_null CreateUnsupportedMessage( MTPDmessage::Flags flags, MsgId replyTo, UserId viaBotId, - QDateTime date, + TimeId date, UserId from) { const auto siteLink = qsl("https://desktop.telegram.org"); auto text = TextWithEntities{ @@ -75,16 +75,20 @@ HistoryItem::HistoryItem( not_null history, MsgId id, MTPDmessage::Flags flags, - QDateTime date, + TimeId date, UserId from) : id(id) -, date(date) +, _date(date) , _history(history) , _from(from ? App::user(from) : history->peer) , _flags(flags) { App::historyRegItem(this); } +TimeId HistoryItem::date() const { + return _date; +} + void HistoryItem::finishEdition(int oldKeyboardTop) { Auth().data().requestItemViewRefresh(this); invalidateChatsListEntry(); @@ -153,8 +157,7 @@ void HistoryItem::finishEditionToEmpty() { bool HistoryItem::isMediaUnread() const { if (!mentionsMe() && _history->peer->isChannel()) { - auto now = ::date(unixtime()); - auto passed = date.secsTo(now); + auto passed = unixtime() - date(); if (passed >= Global::ChannelsReadMediaPeriod()) { return false; } @@ -332,7 +335,7 @@ bool HistoryItem::allowsForward() const { return false; } -bool HistoryItem::allowsEdit(const QDateTime &now) const { +bool HistoryItem::allowsEdit(TimeId now) const { return false; } @@ -357,9 +360,11 @@ bool HistoryItem::canDelete() const { return false; } -bool HistoryItem::canDeleteForEveryone(const QDateTime &cur) const { +bool HistoryItem::canDeleteForEveryone(TimeId now) const { auto messageToMyself = _history->peer->isSelf(); - auto messageTooOld = messageToMyself ? false : (date.secsTo(cur) >= Global::EditTimeLimit()); + auto messageTooOld = messageToMyself + ? false + : (now >= date() + Global::EditTimeLimit()); if (id < 0 || messageToMyself || messageTooOld || isPost()) { return false; } @@ -443,7 +448,7 @@ ChannelId HistoryItem::channelId() const { } Data::MessagePosition HistoryItem::position() const { - return Data::MessagePosition(toServerTime(date.toTime_t()).v, fullId()); + return Data::MessagePosition(date(), fullId()); } MsgId HistoryItem::replyToId() const { @@ -457,11 +462,11 @@ not_null HistoryItem::author() const { return isPost() ? history()->peer : from(); } -QDateTime HistoryItem::dateOriginal() const { +TimeId HistoryItem::dateOriginal() const { if (const auto forwarded = Get()) { return forwarded->originalDate; } - return date; + return date(); } not_null HistoryItem::senderOriginal() const { @@ -621,6 +626,10 @@ HistoryItem::~HistoryItem() { } } +QDateTime ItemDateTime(not_null item) { + return ParseDateTime(item->date()); +} + ClickHandlerPtr goToMessageClickHandler( not_null item, FullMsgId returnToId) { @@ -658,7 +667,7 @@ not_null HistoryItem::Create( const auto text = HistoryService::PreparedText { lang(lng_message_empty) }; - return new HistoryService(history, data.vid.v, ::date(), text); + return new HistoryService(history, data.vid.v, TimeId(0), text); } break; case mtpc_message: { @@ -750,7 +759,7 @@ not_null HistoryItem::Create( data.vflags.v, data.vreply_to_msg_id.v, data.vvia_bot_id.v, - ::date(data.vdate), + data.vdate.v, data.vfrom_id.v); } else if (badMedia == MediaCheckResult::Empty) { const auto text = HistoryService::PreparedText { @@ -759,7 +768,7 @@ not_null HistoryItem::Create( return new HistoryService( history, data.vid.v, - ::date(data.vdate), + data.vdate.v, text, data.vflags.v, data.has_from_id() ? data.vfrom_id.v : UserId(0)); diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index c1e8af56b..177096626 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -207,9 +207,9 @@ public: bool isPinned() const; bool canPin() const; virtual bool allowsForward() const; - virtual bool allowsEdit(const QDateTime &now) const; + virtual bool allowsEdit(TimeId now) const; bool canDelete() const; - bool canDeleteForEveryone(const QDateTime &cur) const; + bool canDeleteForEveryone(TimeId now) const; bool suggestBanReport() const; bool suggestDeleteAllReport() const; @@ -217,13 +217,13 @@ public: QString directLink() const; MsgId id; - QDateTime date; ChannelId channelId() const; FullMsgId fullId() const { return FullMsgId(channelId(), id); } Data::MessagePosition position() const; + TimeId date() const; Data::Media *media() const { return _media.get(); @@ -244,7 +244,7 @@ public: not_null author() const; - QDateTime dateOriginal() const; + TimeId dateOriginal() const; not_null senderOriginal() const; not_null fromOriginal() const; QString authorOriginal() const; @@ -264,7 +264,7 @@ protected: not_null history, MsgId id, MTPDmessage::Flags flags, - QDateTime date, + TimeId date, UserId from); virtual void markMediaAsReadHook() { @@ -296,6 +296,8 @@ protected: std::unique_ptr _media; private: + TimeId _date = 0; + HistoryView::Element *_mainView = nullptr; friend class HistoryView::Element; @@ -303,6 +305,8 @@ private: }; +QDateTime ItemDateTime(not_null item); + ClickHandlerPtr goToMessageClickHandler( not_null peer, MsgId msgId, diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index ca2cda783..5efa9d291 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -45,14 +45,14 @@ struct HistoryMessageEdited : public RuntimeComponent { void create(const HistoryMessageVia *via) const; - QDateTime originalDate; + TimeId originalDate = 0; PeerData *originalSender = nullptr; QString originalAuthor; MsgId originalId = 0; diff --git a/Telegram/SourceFiles/history/history_media_types.cpp b/Telegram/SourceFiles/history/history_media_types.cpp index 86175680b..33002f6ab 100644 --- a/Telegram/SourceFiles/history/history_media_types.cpp +++ b/Telegram/SourceFiles/history/history_media_types.cpp @@ -3144,7 +3144,7 @@ HistoryCall::HistoryCall( const auto item = parent->data(); _text = Data::MediaCall::Text(item, _reason); - _status = item->date.time().toString(cTimeFormat()); + _status = parent->dateTime().time().toString(cTimeFormat()); if (_duration) { if (_reason != FinishReason::Missed && _reason != FinishReason::Busy) { diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 5683d2f79..fa27886cc 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -271,8 +271,8 @@ struct HistoryMessage::CreateConfig { PeerId savedFromPeer = 0; MsgId savedFromMsgId = 0; QString authorOriginal; - QDateTime originalDate; - QDateTime editDate; + TimeId originalDate = 0; + TimeId editDate = 0; // For messages created from MTP structs. const MTPReplyMarkup *mtpMarkup = nullptr; @@ -283,13 +283,18 @@ struct HistoryMessage::CreateConfig { HistoryMessage::HistoryMessage( not_null history, - const MTPDmessage &msg) -: HistoryItem(history, msg.vid.v, msg.vflags.v, ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) { + const MTPDmessage &data) +: HistoryItem( + history, + data.vid.v, + data.vflags.v, + data.vdate.v, + data.has_from_id() ? data.vfrom_id.v : UserId(0)) { CreateConfig config; - if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) { - auto &f = msg.vfwd_from.c_messageFwdHeader(); - config.originalDate = ::date(f.vdate); + if (data.has_fwd_from() && data.vfwd_from.type() == mtpc_messageFwdHeader) { + auto &f = data.vfwd_from.c_messageFwdHeader(); + config.originalDate = f.vdate.v; if (f.has_from_id() || f.has_channel_id()) { config.senderOriginal = f.has_channel_id() ? peerFromChannel(f.vchannel_id) @@ -302,45 +307,50 @@ HistoryMessage::HistoryMessage( } } } - if (msg.has_reply_to_msg_id()) config.replyTo = msg.vreply_to_msg_id.v; - if (msg.has_via_bot_id()) config.viaBotId = msg.vvia_bot_id.v; - if (msg.has_views()) config.viewsCount = msg.vviews.v; - if (msg.has_reply_markup()) config.mtpMarkup = &msg.vreply_markup; - if (msg.has_edit_date()) config.editDate = ::date(msg.vedit_date); - if (msg.has_post_author()) config.author = qs(msg.vpost_author); + if (data.has_reply_to_msg_id()) config.replyTo = data.vreply_to_msg_id.v; + if (data.has_via_bot_id()) config.viaBotId = data.vvia_bot_id.v; + if (data.has_views()) config.viewsCount = data.vviews.v; + if (data.has_reply_markup()) config.mtpMarkup = &data.vreply_markup; + if (data.has_edit_date()) config.editDate = data.vedit_date.v; + if (data.has_post_author()) config.author = qs(data.vpost_author); createComponents(config); - if (msg.has_media()) { - setMedia(msg.vmedia); + if (data.has_media()) { + setMedia(data.vmedia); } - auto text = TextUtilities::Clean(qs(msg.vmessage)); - auto entities = msg.has_entities() - ? TextUtilities::EntitiesFromMTP(msg.ventities.v) + auto text = TextUtilities::Clean(qs(data.vmessage)); + auto entities = data.has_entities() + ? TextUtilities::EntitiesFromMTP(data.ventities.v) : EntitiesInText(); setText({ text, entities }); - if (msg.has_grouped_id()) { - setGroupId(MessageGroupId::FromRaw(msg.vgrouped_id.v)); + if (data.has_grouped_id()) { + setGroupId(MessageGroupId::FromRaw(data.vgrouped_id.v)); } } HistoryMessage::HistoryMessage( not_null history, - const MTPDmessageService &msg) -: HistoryItem(history, msg.vid.v, mtpCastFlags(msg.vflags.v), ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) { + const MTPDmessageService &data) +: HistoryItem( + history, + data.vid.v, + mtpCastFlags(data.vflags.v), + data.vdate.v, + data.has_from_id() ? data.vfrom_id.v : UserId(0)) { CreateConfig config; - if (msg.has_reply_to_msg_id()) config.replyTo = msg.vreply_to_msg_id.v; + if (data.has_reply_to_msg_id()) config.replyTo = data.vreply_to_msg_id.v; createComponents(config); - switch (msg.vaction.type()) { + switch (data.vaction.type()) { case mtpc_messageActionPhoneCall: { _media = std::make_unique( this, - msg.vaction.c_messageActionPhoneCall()); + data.vaction.c_messageActionPhoneCall()); } break; default: Unexpected("Service message action type in HistoryMessage."); @@ -353,21 +363,26 @@ HistoryMessage::HistoryMessage( not_null history, MsgId id, MTPDmessage::Flags flags, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, - not_null fwd) -: HistoryItem(history, id, NewForwardedFlags(history->peer, from, fwd) | flags, date, from) { + not_null original) +: HistoryItem( + history, + id, + NewForwardedFlags(history->peer, from, original) | flags, + date, + from) { CreateConfig config; - if (fwd->Has() || !fwd->history()->peer->isSelf()) { + if (original->Has() || !original->history()->peer->isSelf()) { // Server doesn't add "fwd_from" to non-forwarded messages from chat with yourself. - config.originalDate = fwd->dateOriginal(); - auto senderOriginal = fwd->senderOriginal(); + config.originalDate = original->dateOriginal(); + auto senderOriginal = original->senderOriginal(); config.senderOriginal = senderOriginal->id; - config.authorOriginal = fwd->authorOriginal(); + config.authorOriginal = original->authorOriginal(); if (senderOriginal->isChannel()) { - config.originalId = fwd->idOriginal(); + config.originalId = original->idOriginal(); } } if (history->peer->isSelf()) { @@ -379,16 +394,16 @@ HistoryMessage::HistoryMessage( // config.savedFromPeer = config.senderOriginal; // config.savedFromMsgId = config.originalId; //} else { - config.savedFromPeer = fwd->history()->peer->id; - config.savedFromMsgId = fwd->id; + config.savedFromPeer = original->history()->peer->id; + config.savedFromMsgId = original->id; //} } if (flags & MTPDmessage::Flag::f_post_author) { config.author = postAuthor; } - auto fwdViaBot = fwd->viaBot(); + auto fwdViaBot = original->viaBot(); if (fwdViaBot) config.viaBotId = peerToUser(fwdViaBot->id); - int fwdViewsCount = fwd->viewsCount(); + int fwdViewsCount = original->viewsCount(); if (fwdViewsCount > 0) { config.viewsCount = fwdViewsCount; } else if (isPost()) { @@ -396,9 +411,9 @@ HistoryMessage::HistoryMessage( } // Copy inline keyboard when forwarding messages with a game. - auto mediaOriginal = fwd->media(); + auto mediaOriginal = original->media(); if (mediaOriginal && mediaOriginal->game()) { - config.inlineMarkup = fwd->inlineReplyMarkup(); + config.inlineMarkup = original->inlineReplyMarkup(); } createComponents(config); @@ -416,7 +431,7 @@ HistoryMessage::HistoryMessage( if (mediaOriginal && !ignoreMedia()) { _media = mediaOriginal->clone(this); } - setText(fwd->originalText()); + setText(original->originalText()); } HistoryMessage::HistoryMessage( @@ -425,7 +440,7 @@ HistoryMessage::HistoryMessage( MTPDmessage::Flags flags, MsgId replyTo, UserId viaBotId, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, const TextWithEntities &textWithEntities) @@ -437,17 +452,17 @@ HistoryMessage::HistoryMessage( HistoryMessage::HistoryMessage( not_null history, - MsgId msgId, + MsgId id, MTPDmessage::Flags flags, MsgId replyTo, UserId viaBotId, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, not_null document, const TextWithEntities &caption, const MTPReplyMarkup &markup) -: HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { +: HistoryItem(history, id, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { createComponentsHelper(flags, replyTo, viaBotId, postAuthor, markup); _media = std::make_unique(this, document); @@ -456,17 +471,17 @@ HistoryMessage::HistoryMessage( HistoryMessage::HistoryMessage( not_null history, - MsgId msgId, + MsgId id, MTPDmessage::Flags flags, MsgId replyTo, UserId viaBotId, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, not_null photo, const TextWithEntities &caption, const MTPReplyMarkup &markup) -: HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { +: HistoryItem(history, id, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { createComponentsHelper(flags, replyTo, viaBotId, postAuthor, markup); _media = std::make_unique(this, photo); @@ -475,16 +490,16 @@ HistoryMessage::HistoryMessage( HistoryMessage::HistoryMessage( not_null history, - MsgId msgId, + MsgId id, MTPDmessage::Flags flags, MsgId replyTo, UserId viaBotId, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, not_null game, const MTPReplyMarkup &markup) -: HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { +: HistoryItem(history, id, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { createComponentsHelper(flags, replyTo, viaBotId, postAuthor, markup); _media = std::make_unique(this, game); @@ -564,7 +579,7 @@ bool HistoryMessage::allowsForward() const { return !_media || _media->allowsForward(); } -bool HistoryMessage::allowsEdit(const QDateTime &now) const { +bool HistoryMessage::allowsEdit(TimeId now) const { const auto peer = _history->peer; const auto messageToMyself = peer->isSelf(); const auto canPinInMegagroup = [&] { @@ -575,7 +590,7 @@ bool HistoryMessage::allowsEdit(const QDateTime &now) const { }(); const auto messageTooOld = (messageToMyself || canPinInMegagroup) ? false - : (date.secsTo(now) >= Global::EditTimeLimit()); + : (now >= date() + Global::EditTimeLimit()); if (id < 0 || messageTooOld) { return false; } @@ -626,7 +641,7 @@ void HistoryMessage::createComponents(const CreateConfig &config) { } return (config.inlineMarkup != nullptr); }; - if (!config.editDate.isNull()) { + if (config.editDate != TimeId(0)) { mask |= HistoryMessageEdited::Bit(); } if (config.senderOriginal) { @@ -866,7 +881,7 @@ void HistoryMessage::applyEdition(const MTPDmessage &message) { AddComponents(HistoryMessageEdited::Bit()); } auto edited = Get(); - edited->date = ::date(message.vedit_date); + edited->date = message.vedit_date.v; } TextWithEntities textWithEntities = { qs(message.vmessage), EntitiesInText() }; diff --git a/Telegram/SourceFiles/history/history_message.h b/Telegram/SourceFiles/history/history_message.h index 8b8e045d7..2bb07e49a 100644 --- a/Telegram/SourceFiles/history/history_message.h +++ b/Telegram/SourceFiles/history/history_message.h @@ -29,35 +29,35 @@ class HistoryMessage public: HistoryMessage( not_null history, - const MTPDmessage &msg); + const MTPDmessage &data); HistoryMessage( not_null history, - const MTPDmessageService &msg); + const MTPDmessageService &data); HistoryMessage( not_null history, - MsgId msgId, + MsgId id, MTPDmessage::Flags flags, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, - not_null fwd); // local forwarded + not_null original); // local forwarded HistoryMessage( not_null history, - MsgId msgId, + MsgId id, MTPDmessage::Flags flags, MsgId replyTo, UserId viaBotId, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, const TextWithEntities &textWithEntities); // local message HistoryMessage( not_null history, - MsgId msgId, + MsgId id, MTPDmessage::Flags flags, MsgId replyTo, UserId viaBotId, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, not_null document, @@ -65,11 +65,11 @@ public: const MTPReplyMarkup &markup); // local document HistoryMessage( not_null history, - MsgId msgId, + MsgId id, MTPDmessage::Flags flags, MsgId replyTo, UserId viaBotId, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, not_null photo, @@ -77,11 +77,11 @@ public: const MTPReplyMarkup &markup); // local photo HistoryMessage( not_null history, - MsgId msgId, + MsgId id, MTPDmessage::Flags flags, MsgId replyTo, UserId viaBotId, - QDateTime date, + TimeId date, UserId from, const QString &postAuthor, not_null game, @@ -95,7 +95,7 @@ public: const MTPMessageMedia &media); bool allowsForward() const override; - bool allowsEdit(const QDateTime &now) const override; + bool allowsEdit(TimeId now) const override; bool uploading() const; void applyGroupAdminChanges( diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index afa4f2d0d..d05e67898 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -400,32 +400,39 @@ HistoryService::PreparedText HistoryService::preparePaymentSentText() { return result; } -HistoryService::HistoryService(not_null history, const MTPDmessage &message) : - HistoryItem(history, message.vid.v, message.vflags.v, ::date(message.vdate), message.has_from_id() ? message.vfrom_id.v : 0) { - createFromMtp(message); -} - HistoryService::HistoryService( not_null history, - const MTPDmessageService &message) + const MTPDmessage &data) : HistoryItem( history, - message.vid.v, - mtpCastFlags(message.vflags.v), - ::date(message.vdate), - message.has_from_id() ? message.vfrom_id.v : 0) { - createFromMtp(message); + data.vid.v, + data.vflags.v, + data.vdate.v, + data.has_from_id() ? data.vfrom_id.v : UserId(0)) { + createFromMtp(data); } HistoryService::HistoryService( not_null history, - MsgId msgId, - QDateTime date, + const MTPDmessageService &data) +: HistoryItem( + history, + data.vid.v, + mtpCastFlags(data.vflags.v), + data.vdate.v, + data.has_from_id() ? data.vfrom_id.v : UserId(0)) { + createFromMtp(data); +} + +HistoryService::HistoryService( + not_null history, + MsgId id, + TimeId date, const PreparedText &message, MTPDmessage::Flags flags, UserId from, PhotoData *photo) -: HistoryItem(history, msgId, flags, date, from) { +: HistoryItem(history, id, flags, date, from) { setServiceText(message); if (photo) { _media = std::make_unique( @@ -665,7 +672,7 @@ HistoryService::PreparedText GenerateJoinedText( HistoryService *GenerateJoinedMessage( not_null history, - const QDateTime &inviteDate, + TimeId inviteDate, not_null inviter, MTPDmessage::Flags flags) { return new HistoryService( diff --git a/Telegram/SourceFiles/history/history_service.h b/Telegram/SourceFiles/history/history_service.h index 053b2e4a4..2fae633c7 100644 --- a/Telegram/SourceFiles/history/history_service.h +++ b/Telegram/SourceFiles/history/history_service.h @@ -58,14 +58,14 @@ public: QList links; }; - HistoryService(not_null history, const MTPDmessage &message); + HistoryService(not_null history, const MTPDmessage &data); HistoryService( not_null history, - const MTPDmessageService &message); + const MTPDmessageService &data); HistoryService( not_null history, - MsgId msgId, - QDateTime date, + MsgId id, + TimeId date, const PreparedText &message, MTPDmessage::Flags flags = 0, UserId from = 0, @@ -153,6 +153,6 @@ private: HistoryService *GenerateJoinedMessage( not_null history, - const QDateTime &inviteDate, + TimeId inviteDate, not_null inviter, MTPDmessage::Flags flags); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 05b4cbf01..f911b8f04 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -5137,7 +5137,9 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) { } } else if (e->key() == Qt::Key_Up) { if (!(e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier))) { - if (_history && _history->lastSentMsg && _history->lastSentMsg->allowsEdit(::date(unixtime()))) { + if (_history + && _history->lastSentMsg + && _history->lastSentMsg->allowsEdit(unixtime())) { if (_field->isEmpty() && !_editMsgId && !_replyToId && _history->lastSentMsg) { editMessage(_history->lastSentMsg); return; @@ -5490,7 +5492,7 @@ bool HistoryWidget::sendExistingDocument( flags, 0, options.replyTo, - date(MTP_int(unixtime())), + unixtime(), messageFromId, messagePostAuthor, doc, @@ -5586,7 +5588,7 @@ void HistoryWidget::sendExistingPhoto( flags, 0, options.replyTo, - date(MTP_int(unixtime())), + unixtime(), messageFromId, messagePostAuthor, photo, @@ -6539,8 +6541,7 @@ void HistoryWidget::paintEditHeader(Painter &p, const QRect &rect, int left, int QString editTimeLeftText; int updateIn = -1; - auto tmp = ::date(unixtime()); - auto timeSinceMessage = _replyEditMsg->date.msecsTo(QDateTime::currentDateTime()); + auto timeSinceMessage = ItemDateTime(_replyEditMsg).msecsTo(QDateTime::currentDateTime()); auto editTimeLeft = (Global::EditTimeLimit() * 1000LL) - timeSinceMessage; if (editTimeLeft < 2) { editTimeLeftText = qsl("0:00"); diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 8f04e0dc7..a84ae7957 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -137,6 +137,7 @@ Element::Element( not_null data) : _delegate(delegate) , _data(data) +, _dateTime(ItemDateTime(data)) , _context(delegate->elementContext()) { Auth().data().registerItemView(this); refreshMedia(); @@ -153,6 +154,10 @@ not_null Element::data() const { return _data; } +QDateTime Element::dateTime() const { + return _dateTime; +} + HistoryMedia *Element::media() const { return _media.get(); } @@ -287,7 +292,7 @@ bool Element::computeIsAttachToPrevious(not_null previous) { const auto prev = previous->data(); const auto possible = !item->serviceMsg() && !prev->serviceMsg() && !item->isEmpty() && !prev->isEmpty() - && (qAbs(prev->date.secsTo(item->date)) < kAttachMessageToPreviousSecondsDelta) + && (std::abs(prev->date() - item->date()) < kAttachMessageToPreviousSecondsDelta) && (_context == Context::Feed || (!item->isPost() && !prev->isPost())); if (possible) { @@ -367,9 +372,10 @@ void Element::recountDisplayDateInBlocks() { return false; } - if (auto previous = previousInBlocks()) { + if (const auto previous = previousInBlocks()) { const auto prev = previous->data(); - return prev->isEmpty() || (prev->date.date() != item->date.date()); + return prev->isEmpty() + || (previous->dateTime().date() != dateTime().date()); } return true; }()); @@ -391,7 +397,7 @@ void Element::setDisplayDate(bool displayDate) { const auto item = data(); if (displayDate && !Has()) { AddComponents(DateBadge::Bit()); - Get()->init(item->date); + Get()->init(dateTime()); setPendingResize(); } else if (!displayDate && Has()) { RemoveComponents(DateBadge::Bit()); @@ -478,8 +484,8 @@ bool Element::displayEditedBadge() const { return false; } -QDateTime Element::displayedEditDate() const { - return QDateTime(); +TimeId Element::displayedEditDate() const { + return TimeId(0); } bool Element::hasVisibleText() const { diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index fde010dd8..a020d49a1 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -121,6 +121,8 @@ public: Context context() const; void refreshDataId(); + QDateTime dateTime() const; + int y() const; void setY(int y); @@ -221,7 +223,7 @@ public: int outerWidth) const; virtual ClickHandlerPtr rightActionLink() const; virtual bool displayEditedBadge() const; - virtual QDateTime displayedEditDate() const; + virtual TimeId displayedEditDate() const; virtual bool hasVisibleText() const; // Legacy blocks structure. @@ -266,9 +268,10 @@ private: const not_null _delegate; const not_null _data; std::unique_ptr _media; + const QDateTime _dateTime; int _y = 0; - Context _context; + Context _context = Context(); Flags _flags = Flag::NeedsResize; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 8b62827d5..26d0b68be 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -908,7 +908,7 @@ QString ListWidget::tooltipText() const { ? _overElement->data().get() : nullptr; if (_mouseCursorState == CursorState::Date && item) { - return item->date.toString( + return _overElement->dateTime().toString( QLocale::system().dateTimeFormat(QLocale::LongFormat)); } else if (_mouseCursorState == CursorState::Forwarded && item) { if (const auto forwarded = item->Get()) { @@ -1178,7 +1178,7 @@ void ListWidget::paintEvent(QPaintEvent *e) { } else { ServiceMessagePainter::paintDate( p, - view->data()->date, + view->dateTime(), dateY, width); } @@ -1238,7 +1238,7 @@ TextWithEntities ListWidget::getSelectedText() const { const auto wrapItem = [&]( not_null item, TextWithEntities &&unwrapped) { - auto time = item->date.toString(timeFormat); + auto time = ItemDateTime(item).toString(timeFormat); auto part = TextWithEntities(); auto size = item->author()->name.size() + time.size() @@ -2158,8 +2158,8 @@ void ListWidget::refreshAttachmentsFromTill(int from, int till) { if (next->isHidden()) { next->setDisplayDate(false); } else { - const auto viewDate = view->data()->date; - const auto nextDate = next->data()->date; + const auto viewDate = view->dateTime(); + const auto nextDate = next->dateTime(); next->setDisplayDate(nextDate.date() != viewDate.date()); auto attached = next->computeIsAttachToPrevious(view); next->setAttachToPrevious(attached); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 9d57cce10..b7138adf9 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1682,12 +1682,12 @@ void Message::refreshEditedBadge() { const auto item = message(); const auto edited = displayedEditBadge(); const auto editDate = displayedEditDate(); - const auto dateText = item->date.toString(cTimeFormat()); + const auto dateText = dateTime().toString(cTimeFormat()); if (edited) { - edited->refresh(dateText, !editDate.isNull()); + edited->refresh(dateText, editDate != 0); } if (const auto msgsigned = item->Get()) { - const auto text = (!edited || editDate.isNull()) + const auto text = (!edited || !editDate) ? dateText : edited->text.originalText(); msgsigned->refresh(text); @@ -1702,7 +1702,7 @@ void Message::initTime() { } else if (const auto edited = displayedEditBadge()) { item->_timeWidth = edited->maxWidth(); } else { - item->_timeText = item->date.toString(cTimeFormat()); + item->_timeText = dateTime().toString(cTimeFormat()); item->_timeWidth = st::msgDateFont->width(item->_timeText); } if (const auto views = item->Get()) { @@ -1722,29 +1722,29 @@ void Message::initTime() { } bool Message::displayEditedBadge() const { - return !displayedEditDate().isNull(); + return (displayedEditDate() != TimeId(0)); } -QDateTime Message::displayedEditDate() const { +TimeId Message::displayedEditDate() const { const auto item = message(); auto hasViaBotId = item->Has(); auto hasInlineMarkup = (item->inlineReplyMarkup() != nullptr); return displayedEditDate(hasViaBotId || hasInlineMarkup); } -QDateTime Message::displayedEditDate( +TimeId Message::displayedEditDate( bool hasViaBotOrInlineMarkup) const { if (hasViaBotOrInlineMarkup) { - return QDateTime(); + return TimeId(0); } else if (const auto fromUser = message()->from()->asUser()) { if (fromUser->botInfo) { - return QDateTime(); + return TimeId(0); } } if (const auto edited = displayedEditBadge()) { return edited->date; } - return QDateTime(); + return TimeId(0); } HistoryMessageEdited *Message::displayedEditBadge() { diff --git a/Telegram/SourceFiles/history/view/history_view_message.h b/Telegram/SourceFiles/history/view/history_view_message.h index 9286cadea..09f82592e 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.h +++ b/Telegram/SourceFiles/history/view/history_view_message.h @@ -79,7 +79,7 @@ public: int outerWidth) const override; ClickHandlerPtr rightActionLink() const override; bool displayEditedBadge() const override; - QDateTime displayedEditDate() const override; + TimeId displayedEditDate() const override; int infoWidth() const override; private: @@ -135,7 +135,7 @@ private: bool displayFastShare() const; bool displayGoToOriginal() const; ClickHandlerPtr fastReplyLink() const; - QDateTime displayedEditDate(bool hasViaBotOrInlineMarkup) const; + TimeId displayedEditDate(bool hasViaBotOrInlineMarkup) const; const HistoryMessageEdited *displayedEditBadge() const; HistoryMessageEdited *displayedEditBadge(); void initTime(); diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 6d4c7a904..266534fc3 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -194,7 +194,7 @@ bool ListWidget::Section::addItem(not_null item) { void ListWidget::Section::setHeader(not_null item) { auto text = [&] { - auto date = item->getItem()->date.date(); + auto date = item->dateTime().date(); switch (_type) { case Type::Photo: case Type::Video: @@ -217,8 +217,8 @@ void ListWidget::Section::setHeader(not_null item) { bool ListWidget::Section::belongsHere( not_null item) const { Expects(!_items.empty()); - auto date = item->getItem()->date.date(); - auto myDate = _items.back().second->getItem()->date.date(); + auto date = item->dateTime().date(); + auto myDate = _items.back().second->dateTime().date(); switch (_type) { case Type::Photo: diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp index 3e53ed29c..d06dc7a12 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp @@ -131,7 +131,7 @@ void SendPhoto::addToHistory( flags, viaBotId, replyToId, - date(mtpDate), + mtpDate.v, fromId, postAuthor, _photo, @@ -166,7 +166,7 @@ void SendFile::addToHistory( flags, viaBotId, replyToId, - date(mtpDate), + mtpDate.v, fromId, postAuthor, _document, @@ -208,7 +208,7 @@ void SendGame::addToHistory( flags, viaBotId, replyToId, - date(mtpDate), + mtpDate.v, fromId, postAuthor, _game, diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index c1daef1a4..0a5af556f 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4860,16 +4860,20 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateContactRegistered: { - auto &d = update.c_updateContactRegistered(); - if (auto user = App::userLoaded(d.vuser_id.v)) { + const auto &d = update.c_updateContactRegistered(); + if (const auto user = App::userLoaded(d.vuser_id.v)) { if (App::history(user->id)->loadedAtBottom()) { - App::history(user->id)->addNewService(clientMsgId(), date(d.vdate), lng_action_user_registered(lt_from, user->name), 0); + App::history(user->id)->addNewService( + clientMsgId(), + d.vdate.v, + lng_action_user_registered(lt_from, user->name), + MTPDmessage::Flags(0)); } } } break; case mtpc_updateContactLink: { - auto &d = update.c_updateContactLink(); + const auto &d = update.c_updateContactLink(); App::feedUserLink(d.vuser_id, d.vmy_link, d.vforeign_link); } break; diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp index 1cc63129c..4977c2246 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.cpp +++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp @@ -468,22 +468,31 @@ void Widget::handleSongChange() { TextWithEntities textWithEntities; if (document->isVoiceMessage() || document->isVideoMessage()) { - if (auto item = App::histItemById(current.contextId())) { - auto name = App::peerName(item->fromOriginal()); - auto date = [item] { - auto date = item->date.date(); - auto time = item->date.time().toString(cTimeFormat()); - auto today = QDateTime::currentDateTime().date(); + if (const auto item = App::histItemById(current.contextId())) { + const auto name = App::peerName(item->fromOriginal()); + const auto date = [item] { + const auto parsed = ItemDateTime(item); + const auto date = parsed.date(); + const auto time = parsed.time().toString(cTimeFormat()); + const auto today = QDateTime::currentDateTime().date(); if (date == today) { return lng_player_message_today(lt_time, time); } else if (date.addDays(1) == today) { return lng_player_message_yesterday(lt_time, time); } - return lng_player_message_date(lt_date, langDayOfMonthFull(date), lt_time, time); + return lng_player_message_date( + lt_date, + langDayOfMonthFull(date), + lt_time, + time); }; textWithEntities.text = name + ' ' + date(); - textWithEntities.entities.append({ EntityInTextBold, 0, name.size(), QString() }); + textWithEntities.entities.append(EntityInText( + EntityInTextBold, + 0, + name.size(), + QString())); } else { textWithEntities.text = lang(lng_media_audio); } diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 9553c26c5..1ed0f7aa8 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -325,14 +325,17 @@ void MediaView::updateControls() { _moreNav = myrtlrect(width() - st::mediaviewIconSize.width(), height() - st::mediaviewIconSize.height(), st::mediaviewIconSize.width(), st::mediaviewIconSize.height()); _moreNavIcon = centerrect(_moreNav, st::mediaviewMore); - QDateTime d, dNow(date(unixtime())); - if (_photo) { - d = date(_photo->date); - } else if (_doc) { - d = date(_doc->date); - } else if (auto item = App::histItemById(_msgid)) { - d = item->date; - } + const auto dNow = QDateTime::currentDateTime(); + const auto d = [&] { + if (_photo) { + return ParseDateTime(_photo->date); + } else if (_doc) { + return ParseDateTime(_doc->date); + } else if (const auto item = App::histItemById(_msgid)) { + return ItemDateTime(item); + } + return dNow; + }(); if (d.date() == dNow.date()) { _dateText = lng_mediaview_today(lt_time, d.time().toString(cTimeFormat())); } else if (d.date().addDays(1) == dNow.date()) { @@ -847,14 +850,23 @@ void MediaView::onSaveAs() { psBringToBack(this); auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter(); - FileDialog::GetWritePath(lang(lng_save_photo), filter, filedialogDefaultName(qsl("photo"), qsl(".jpg"), QString(), false, _photo->date), base::lambda_guarded(this, [this, photo = _photo](const QString &result) { - if (!result.isEmpty() && _photo == photo && photo->loaded()) { - photo->full->pix().toImage().save(result, "JPG"); - } - psShowOverAll(this); - }), base::lambda_guarded(this, [this] { - psShowOverAll(this); - })); + FileDialog::GetWritePath( + lang(lng_save_photo), + filter, + filedialogDefaultName( + qsl("photo"), + qsl(".jpg"), + QString(), + false, + _photo->date), + base::lambda_guarded(this, [this, photo = _photo](const QString &result) { + if (!result.isEmpty() && _photo == photo && photo->loaded()) { + photo->full->pix().toImage().save(result, "JPG"); + } + psShowOverAll(this); + }), base::lambda_guarded(this, [this] { + psShowOverAll(this); + })); } activateWindow(); Sandbox::setActiveWindow(this); diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index af634ca8b..55ff0179d 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -124,7 +124,13 @@ MsgId AbstractItem::msgId() const { return item ? item->id : 0; } -ItemBase::ItemBase(not_null parent) : _parent(parent) { +ItemBase::ItemBase(not_null parent) +: _parent(parent) +, _dateTime(ItemDateTime(parent)) { +} + +QDateTime ItemBase::dateTime() const { + return _dateTime; } void ItemBase::clickHandlerActiveChanged( @@ -564,9 +570,19 @@ Voice::Voice( setDocumentLinks(_data); updateName(); - QString d = textcmdLink(1, TextUtilities::EscapeForRichParsing(langDateTime(date(_data->date)))); + const auto dateText = textcmdLink( + 1, + TextUtilities::EscapeForRichParsing( + langDateTime(ParseDateTime(_data->date)))); TextParseOptions opts = { TextParseRichText, 0, 0, Qt::LayoutDirectionAuto }; - _details.setText(st::defaultTextStyle, lng_date_and_duration(lt_date, d, lt_duration, formatDurationText(_data->voice()->duration)), opts); + _details.setText( + st::defaultTextStyle, + lng_date_and_duration( + lt_date, + dateText, + lt_duration, + formatDurationText(_data->voice()->duration)), + opts); _details.setLink(1, goToMessageClickHandler(parent)); } @@ -804,7 +820,7 @@ Document::Document( , _msgl(goToMessageClickHandler(parent)) , _namel(std::make_shared(_data, parent->fullId())) , _st(st) -, _date(langDateTime(date(_data->date))) +, _date(langDateTime(ParseDateTime(_data->date))) , _datew(st::normalFont->width(_date)) , _colorIndex(documentColorIndex(_data, _ext)) { _name.setMarkedText(st::defaultTextStyle, ComposeNameWithEntities(_data), _documentNameOptions); diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h index 7fe98e701..4444e0a1d 100644 --- a/Telegram/SourceFiles/overview/overview_layout.h +++ b/Telegram/SourceFiles/overview/overview_layout.h @@ -64,6 +64,8 @@ class ItemBase : public AbstractItem { public: ItemBase(not_null parent); + QDateTime dateTime() const; + void setPosition(int position) { _position = position; } @@ -103,7 +105,8 @@ private: void ensureCheckboxCreated(); int _position = 0; - not_null _parent; + const not_null _parent; + const QDateTime _dateTime; std::unique_ptr _check; }; diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp index 3376fc88c..26530ae38 100644 --- a/Telegram/SourceFiles/window/notifications_manager.cpp +++ b/Telegram/SourceFiles/window/notifications_manager.cpp @@ -331,7 +331,9 @@ void System::showNext() { if (nextNotify) { if (forwardedItem) { auto nextForwarded = nextNotify->Has() ? nextNotify : nullptr; - if (nextForwarded && forwardedItem->author() == nextForwarded->author() && qAbs(int64(nextForwarded->date.toTime_t()) - int64(forwardedItem->date.toTime_t())) < 2) { + if (nextForwarded + && forwardedItem->author() == nextForwarded->author() + && qAbs(int64(nextForwarded->date()) - int64(forwardedItem->date())) < 2) { forwardedItem = nextForwarded; ++forwardedCount; } else { diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index fd96720a0..31994a994 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -309,13 +309,13 @@ void Controller::showJumpToDate(not_null peer, QDate requestedDate) { auto currentPeerDate = [peer] { if (auto history = App::historyLoaded(peer)) { if (history->scrollTopItem) { - return history->scrollTopItem->data()->date.date(); + return history->scrollTopItem->dateTime().date(); } else if (history->loadedAtTop() && !history->isEmpty() && history->peer->migrateFrom()) { if (auto migrated = App::historyLoaded(history->peer->migrateFrom())) { if (migrated->scrollTopItem) { // We're up in the migrated history. // So current date is the date of first message here. - return history->blocks.front()->messages.front()->data()->date.date(); + return history->blocks.front()->messages.front()->dateTime().date(); } } } else if (!history->chatsListDate().isNull()) { @@ -344,7 +344,7 @@ void Controller::showJumpToDate(not_null peer, QDate requestedDate) { if (auto history = App::historyLoaded(chat)) { if (history->loadedAtTop()) { if (!history->isEmpty()) { - return history->blocks.front()->messages.front()->data()->date.date(); + return history->blocks.front()->messages.front()->dateTime().date(); } } else { return startDate(); @@ -354,7 +354,7 @@ void Controller::showJumpToDate(not_null peer, QDate requestedDate) { if (auto history = App::historyLoaded(peer)) { if (history->loadedAtTop()) { if (!history->isEmpty()) { - return history->blocks.front()->messages.front()->data()->date.date(); + return history->blocks.front()->messages.front()->dateTime().date(); } return QDate::currentDate(); }