Request dialog list entries when needed.

Also save the original server-side int32 date in HistoryItems.
This commit is contained in:
John Preston 2018-02-03 22:52:35 +03:00
parent 0c5efb935d
commit 8bacc74d8b
50 changed files with 719 additions and 549 deletions

View file

@ -377,24 +377,6 @@ void ApiWrap::requestDialogEntry(not_null<Data::Feed*> feed) {
auto peers = QVector<MTPInputDialogPeer>(
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<Data::Feed*> feed) {
}).send();
}
//void ApiWrap::requestFeedDialogsEntries(not_null<Data::Feed*> 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*> history) {
if (_dialogRequests.contains(history)) {
return;
@ -417,43 +420,7 @@ void ApiWrap::requestDialogEntry(not_null<History*> 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<MTPMessage>());
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*> 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<MTPMessage>());
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<Data::Feed*> 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<not_null<ChannelData*>>();
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<PeerData*> 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<Data::Feed*> 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<Data::Feed*> 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);

View file

@ -69,6 +69,7 @@ public:
void requestContacts();
void requestDialogEntry(not_null<Data::Feed*> feed);
//void requestFeedDialogsEntries(not_null<Data::Feed*> feed);
void requestDialogEntry(not_null<History*> history);
void requestFullPeer(PeerData *peer);
@ -282,6 +283,10 @@ private:
QVector<MTPint> collectMessageIds(const MessageDataRequests &requests);
MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false);
void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs);
void historyDialogEntryApplied(not_null<History*> history);
void applyFeedDialogs(
not_null<Data::Feed*> feed,
const MTPmessages_Dialogs &dialogs);
void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req);
void gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestId req);

View file

@ -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);
}
}

View file

@ -415,7 +415,7 @@ MTPChannelBannedRights EditRestrictedBox::DefaultRights(not_null<ChannelData*> 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<CalendarBox>(
@ -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) {

View file

@ -364,15 +364,15 @@ void ContactsBoxController::checkForEmptyRows() {
}
}
std::unique_ptr<PeerListRow> ContactsBoxController::createSearchRow(not_null<PeerData*> peer) {
if (auto user = peer->asUser()) {
std::unique_ptr<PeerListRow> ContactsBoxController::createSearchRow(
not_null<PeerData*> peer) {
if (const auto user = peer->asUser()) {
return createRow(user);
}
return nullptr;
}
void ContactsBoxController::rowClicked(not_null<PeerListRow*> row) {
Auth().api().requestDialogEntry(App::history(row->peer()));
Ui::showPeerHistory(row->peer(), ShowAtUnreadMsgId);
}

View file

@ -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,

View file

@ -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"));

View file

@ -39,7 +39,8 @@ public:
};
bool canAddItem(not_null<const HistoryItem*> item) const {
return (ComputeType(item) == _type && item->date.date() == _date);
return (ComputeType(item) == _type)
&& (ItemDateTime(item).date() == _date);
}
void addItem(not_null<HistoryItem*> item) {
Expects(canAddItem(item));
@ -117,7 +118,7 @@ private:
BoxController::Row::Row(not_null<HistoryItem*> 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);

View file

@ -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);

View file

@ -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,

View file

@ -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<TimeMs>(ts.tv_sec) + (static_cast<TimeMs>(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;

View file

@ -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

View file

@ -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<const Ui::FlatTextarea*> 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<Draft>(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();

View file

@ -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<const Ui::FlatTextarea*> 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;

View file

@ -74,7 +74,7 @@ void Feed::registerOne(not_null<ChannelData*> 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<ChannelData*> channel) {
void Feed::updateLastMessage(not_null<HistoryItem*> item) {
if (justUpdateLastMessage(item)) {
if (_lastMessage && *_lastMessage) {
setChatsListDate((*_lastMessage)->date);
setChatsListDate(ItemDateTime(*_lastMessage));
}
}
}
@ -192,15 +192,22 @@ void Feed::setChannels(std::vector<not_null<ChannelData*>> 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<int> 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 {

View file

@ -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;

View file

@ -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);

View file

@ -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<int32>(nowFull.secsTo(tomorrow));
}
@ -175,27 +176,21 @@ TimeId SortByOnlineValue(not_null<UserData*> 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<UserData*> 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);

View file

@ -32,22 +32,6 @@ uint64 PinnedDialogPos(int pinnedIndex) {
} // namespace
bool MessageIsLess(not_null<HistoryItem*> a, not_null<HistoryItem*> 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;

View file

@ -33,8 +33,6 @@ struct PositionChange {
int movedTo;
};
bool MessageIsLess(not_null<HistoryItem*> a, not_null<HistoryItem*> 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;

View file

@ -1716,7 +1716,6 @@ void DialogsInner::dialogsReceived(const QVector<MTPDialog> &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);
}
}
}

View file

@ -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,

View file

@ -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);
}

View file

@ -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<uint64>();
auto mixinIdPart = (static_cast<uint64>(static_cast<uint32>(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<MTPPhotoSize>(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<Flags, LangKey> {
{ 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<HistoryItem*> 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)));
}
};

View file

@ -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<Data::Draft>(draft->textWithTags, draft->msgId, draft->cursor, draft->previewCancelled));
setLocalDraft(std::make_unique<Data::Draft>(
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<Data::Draft>(fromDraft->textWithTags, fromDraft->msgId, fromDraft->cursor, fromDraft->previewCancelled));
setCloudDraft(std::make_unique<Data::Draft>(
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<not_null<HistoryItem*>> History::createItems(
return result;
}
not_null<HistoryItem*> 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<HistoryItem*> 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<HistoryItem*> 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<HistoryItem*> 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<HistoryItem*> 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<HistoryItem*> History::addNewForwarded(
MsgId id,
MTPDmessage::Flags flags,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
HistoryMessage *original) {
not_null<HistoryMessage*> 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<HistoryItem*> History::addNewDocument(
MTPDmessage::Flags flags,
UserId viaBotId,
MsgId replyTo,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
DocumentData *document,
not_null<DocumentData*> 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<HistoryItem*> History::addNewPhoto(
MTPDmessage::Flags flags,
UserId viaBotId,
MsgId replyTo,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
PhotoData *photo,
not_null<PhotoData*> 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<HistoryItem*> History::addNewGame(
MTPDmessage::Flags flags,
UserId viaBotId,
MsgId replyTo,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
GameData *game,
not_null<GameData*> 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<HistoryItem*> 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<AdminLog::LocalIdManager> 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());
}

View file

@ -148,15 +148,56 @@ public:
void unloadBlocks();
void clearUpTill(MsgId availableMinId);
void applyGroupAdminChanges(const base::flat_map<UserId, bool> &changes);
void applyGroupAdminChanges(
const base::flat_map<UserId, bool> &changes);
HistoryItem *addNewMessage(const MTPMessage &msg, NewMessageType type);
HistoryItem *addToHistory(const MTPMessage &msg);
not_null<HistoryItem*> addNewService(MsgId msgId, QDateTime date, const QString &text, MTPDmessage::Flags flags = 0, bool newMsg = true);
not_null<HistoryItem*> addNewForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, UserId from, const QString &postAuthor, HistoryMessage *item);
not_null<HistoryItem*> 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<HistoryItem*> 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<HistoryItem*> addNewGame(MsgId id, MTPDmessage::Flags flags, UserId viaBotId, MsgId replyTo, QDateTime date, UserId from, const QString &postAuthor, GameData *game, const MTPReplyMarkup &markup);
not_null<HistoryItem*> addNewService(
MsgId msgId,
TimeId date,
const QString &text,
MTPDmessage::Flags flags = 0,
bool newMsg = true);
not_null<HistoryItem*> addNewForwarded(
MsgId id,
MTPDmessage::Flags flags,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<HistoryMessage*> original);
not_null<HistoryItem*> addNewDocument(
MsgId id,
MTPDmessage::Flags flags,
UserId viaBotId,
MsgId replyTo,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<DocumentData*> document,
const TextWithEntities &caption,
const MTPReplyMarkup &markup);
not_null<HistoryItem*> addNewPhoto(
MsgId id,
MTPDmessage::Flags flags,
UserId viaBotId,
MsgId replyTo,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<PhotoData*> photo,
const TextWithEntities &caption,
const MTPReplyMarkup &markup);
not_null<HistoryItem*> addNewGame(
MsgId id,
MTPDmessage::Flags flags,
UserId viaBotId,
MsgId replyTo,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<GameData*> 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<HistoryItem*> createItemForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, UserId from, const QString &postAuthor, HistoryMessage *msg);
not_null<HistoryItem*> 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<HistoryItem*> 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<HistoryItem*> createItemGame(MsgId id, MTPDmessage::Flags flags, UserId viaBotId, MsgId replyTo, QDateTime date, UserId from, const QString &postAuthor, GameData *game, const MTPReplyMarkup &markup);
not_null<HistoryItem*> addNewItem(
not_null<HistoryItem*> item,
bool unread);

View file

@ -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<PhotoData*> 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<PhotoData*> photo) {
@ -1797,7 +1803,7 @@ TextWithEntities HistoryInner::getSelectedText() const {
const auto wrapItem = [&](
not_null<HistoryItem*> 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<HistoryView::DateBadge>()) {
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<DateClickHandler>(item->history()->peer, item->date.date());
_scrollDateLink = std::make_shared<DateClickHandler>(item->history()->peer, view->dateTime().date());
} else {
static_cast<DateClickHandler*>(_scrollDateLink.get())->setDate(item->date.date());
static_cast<DateClickHandler*>(_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<HistoryMessageForwarded>()) {
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;
}

View file

@ -47,7 +47,7 @@ not_null<HistoryItem*> 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*> 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<PeerData*> HistoryItem::author() const {
return isPost() ? history()->peer : from();
}
QDateTime HistoryItem::dateOriginal() const {
TimeId HistoryItem::dateOriginal() const {
if (const auto forwarded = Get<HistoryMessageForwarded>()) {
return forwarded->originalDate;
}
return date;
return date();
}
not_null<PeerData*> HistoryItem::senderOriginal() const {
@ -621,6 +626,10 @@ HistoryItem::~HistoryItem() {
}
}
QDateTime ItemDateTime(not_null<const HistoryItem*> item) {
return ParseDateTime(item->date());
}
ClickHandlerPtr goToMessageClickHandler(
not_null<HistoryItem*> item,
FullMsgId returnToId) {
@ -658,7 +667,7 @@ not_null<HistoryItem*> 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*> 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*> 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));

View file

@ -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<PeerData*> author() const;
QDateTime dateOriginal() const;
TimeId dateOriginal() const;
not_null<PeerData*> senderOriginal() const;
not_null<PeerData*> fromOriginal() const;
QString authorOriginal() const;
@ -264,7 +264,7 @@ protected:
not_null<History*> history,
MsgId id,
MTPDmessage::Flags flags,
QDateTime date,
TimeId date,
UserId from);
virtual void markMediaAsReadHook() {
@ -296,6 +296,8 @@ protected:
std::unique_ptr<Data::Media> _media;
private:
TimeId _date = 0;
HistoryView::Element *_mainView = nullptr;
friend class HistoryView::Element;
@ -303,6 +305,8 @@ private:
};
QDateTime ItemDateTime(not_null<const HistoryItem*> item);
ClickHandlerPtr goToMessageClickHandler(
not_null<PeerData*> peer,
MsgId msgId,

View file

@ -45,14 +45,14 @@ struct HistoryMessageEdited : public RuntimeComponent<HistoryMessageEdited, Hist
void refresh(const QString &date, bool displayed);
int maxWidth() const;
QDateTime date;
TimeId date = 0;
Text text;
};
struct HistoryMessageForwarded : public RuntimeComponent<HistoryMessageForwarded, HistoryItem> {
void create(const HistoryMessageVia *via) const;
QDateTime originalDate;
TimeId originalDate = 0;
PeerData *originalSender = nullptr;
QString originalAuthor;
MsgId originalId = 0;

View file

@ -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) {

View file

@ -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*> 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*> 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<Data::MediaCall>(
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*> history,
MsgId id,
MTPDmessage::Flags flags,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<HistoryMessage*> fwd)
: HistoryItem(history, id, NewForwardedFlags(history->peer, from, fwd) | flags, date, from) {
not_null<HistoryMessage*> original)
: HistoryItem(
history,
id,
NewForwardedFlags(history->peer, from, original) | flags,
date,
from) {
CreateConfig config;
if (fwd->Has<HistoryMessageForwarded>() || !fwd->history()->peer->isSelf()) {
if (original->Has<HistoryMessageForwarded>() || !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*> history,
MsgId msgId,
MsgId id,
MTPDmessage::Flags flags,
MsgId replyTo,
UserId viaBotId,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<DocumentData*> 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<Data::MediaFile>(this, document);
@ -456,17 +471,17 @@ HistoryMessage::HistoryMessage(
HistoryMessage::HistoryMessage(
not_null<History*> history,
MsgId msgId,
MsgId id,
MTPDmessage::Flags flags,
MsgId replyTo,
UserId viaBotId,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<PhotoData*> 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<Data::MediaPhoto>(this, photo);
@ -475,16 +490,16 @@ HistoryMessage::HistoryMessage(
HistoryMessage::HistoryMessage(
not_null<History*> history,
MsgId msgId,
MsgId id,
MTPDmessage::Flags flags,
MsgId replyTo,
UserId viaBotId,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<GameData*> 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<Data::MediaGame>(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<HistoryMessageEdited>();
edited->date = ::date(message.vedit_date);
edited->date = message.vedit_date.v;
}
TextWithEntities textWithEntities = { qs(message.vmessage), EntitiesInText() };

View file

@ -29,35 +29,35 @@ class HistoryMessage
public:
HistoryMessage(
not_null<History*> history,
const MTPDmessage &msg);
const MTPDmessage &data);
HistoryMessage(
not_null<History*> history,
const MTPDmessageService &msg);
const MTPDmessageService &data);
HistoryMessage(
not_null<History*> history,
MsgId msgId,
MsgId id,
MTPDmessage::Flags flags,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<HistoryMessage*> fwd); // local forwarded
not_null<HistoryMessage*> original); // local forwarded
HistoryMessage(
not_null<History*> 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*> history,
MsgId msgId,
MsgId id,
MTPDmessage::Flags flags,
MsgId replyTo,
UserId viaBotId,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<DocumentData*> document,
@ -65,11 +65,11 @@ public:
const MTPReplyMarkup &markup); // local document
HistoryMessage(
not_null<History*> history,
MsgId msgId,
MsgId id,
MTPDmessage::Flags flags,
MsgId replyTo,
UserId viaBotId,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<PhotoData*> photo,
@ -77,11 +77,11 @@ public:
const MTPReplyMarkup &markup); // local photo
HistoryMessage(
not_null<History*> history,
MsgId msgId,
MsgId id,
MTPDmessage::Flags flags,
MsgId replyTo,
UserId viaBotId,
QDateTime date,
TimeId date,
UserId from,
const QString &postAuthor,
not_null<GameData*> 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(

View file

@ -400,32 +400,39 @@ HistoryService::PreparedText HistoryService::preparePaymentSentText() {
return result;
}
HistoryService::HistoryService(not_null<History*> 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*> 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*> 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*> 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<Data::MediaPhoto>(
@ -665,7 +672,7 @@ HistoryService::PreparedText GenerateJoinedText(
HistoryService *GenerateJoinedMessage(
not_null<History*> history,
const QDateTime &inviteDate,
TimeId inviteDate,
not_null<UserData*> inviter,
MTPDmessage::Flags flags) {
return new HistoryService(

View file

@ -58,14 +58,14 @@ public:
QList<ClickHandlerPtr> links;
};
HistoryService(not_null<History*> history, const MTPDmessage &message);
HistoryService(not_null<History*> history, const MTPDmessage &data);
HistoryService(
not_null<History*> history,
const MTPDmessageService &message);
const MTPDmessageService &data);
HistoryService(
not_null<History*> 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*> history,
const QDateTime &inviteDate,
TimeId inviteDate,
not_null<UserData*> inviter,
MTPDmessage::Flags flags);

View file

@ -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");

View file

@ -137,6 +137,7 @@ Element::Element(
not_null<HistoryItem*> data)
: _delegate(delegate)
, _data(data)
, _dateTime(ItemDateTime(data))
, _context(delegate->elementContext()) {
Auth().data().registerItemView(this);
refreshMedia();
@ -153,6 +154,10 @@ not_null<HistoryItem*> 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<Element*> 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<DateBadge>()) {
AddComponents(DateBadge::Bit());
Get<DateBadge>()->init(item->date);
Get<DateBadge>()->init(dateTime());
setPendingResize();
} else if (!displayDate && Has<DateBadge>()) {
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 {

View file

@ -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<ElementDelegate*> _delegate;
const not_null<HistoryItem*> _data;
std::unique_ptr<HistoryMedia> _media;
const QDateTime _dateTime;
int _y = 0;
Context _context;
Context _context = Context();
Flags _flags = Flag::NeedsResize;

View file

@ -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<HistoryMessageForwarded>()) {
@ -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<HistoryItem*> 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);

View file

@ -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<HistoryMessageSigned>()) {
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<HistoryMessageViews>()) {
@ -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<HistoryMessageVia>();
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() {

View file

@ -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();

View file

@ -194,7 +194,7 @@ bool ListWidget::Section::addItem(not_null<BaseLayout*> item) {
void ListWidget::Section::setHeader(not_null<BaseLayout*> 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<BaseLayout*> item) {
bool ListWidget::Section::belongsHere(
not_null<BaseLayout*> 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:

View file

@ -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,

View file

@ -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;

View file

@ -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);
}

View file

@ -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);

View file

@ -124,7 +124,13 @@ MsgId AbstractItem::msgId() const {
return item ? item->id : 0;
}
ItemBase::ItemBase(not_null<HistoryItem*> parent) : _parent(parent) {
ItemBase::ItemBase(not_null<HistoryItem*> 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<DocumentOpenClickHandler>(_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);

View file

@ -64,6 +64,8 @@ class ItemBase : public AbstractItem {
public:
ItemBase(not_null<HistoryItem*> parent);
QDateTime dateTime() const;
void setPosition(int position) {
_position = position;
}
@ -103,7 +105,8 @@ private:
void ensureCheckboxCreated();
int _position = 0;
not_null<HistoryItem*> _parent;
const not_null<HistoryItem*> _parent;
const QDateTime _dateTime;
std::unique_ptr<Checkbox> _check;
};

View file

@ -331,7 +331,9 @@ void System::showNext() {
if (nextNotify) {
if (forwardedItem) {
auto nextForwarded = nextNotify->Has<HistoryMessageForwarded>() ? 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 {

View file

@ -309,13 +309,13 @@ void Controller::showJumpToDate(not_null<PeerData*> 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<PeerData*> 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<PeerData*> 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();
}