diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings index a2540285b..dfc9bb12c 100644 --- a/Telegram/Resources/lang.strings +++ b/Telegram/Resources/lang.strings @@ -450,8 +450,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org "lng_action_user_registered" = "{from} just joined Telegram"; "lng_action_removed_photo" = "{from} removed group photo"; "lng_action_removed_photo_channel" = "Channel photo was removed"; -"lng_action_changed_photo" = "{from} changed group photo"; -"lng_action_changed_photo_channel" = "Channel photo was changed"; +"lng_action_changed_photo" = "{from} updated group photo"; +"lng_action_changed_photo_channel" = "Channel photo was updated"; "lng_action_changed_title" = "{from} changed group name to «{title}»"; "lng_action_changed_title_channel" = "Channel name was changed to «{title}»"; "lng_action_created_chat" = "{from} created group «{title}»"; diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index b7bfd8d1a..27a96bb31 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1088,8 +1088,28 @@ btnBotKbHide: iconedButton(btnAttachEmoji) { downIcon: sprite(373px, 95px, 23px, 14px); downIconPos: point(5px, 17px); } -broadcastToggle: sprite(40px, 104px, 22px, 21px); -broadcastToggleOn: sprite(40px, 125px, 22px, 21px); +broadcastToggle: flatCheckbox { + textColor: black; + bgColor: white; + disColor: black; + + width: 36px; + height: 46px; + duration: 200; + bgFunc: transition(easeOutCirc); + cursor: cursor(pointer); + + font: normalFont; + + imageRect: sprite(18px, 125px, 22px, 21px); + chkImageRect: sprite(40px, 125px, 22px, 21px); + overImageRect: sprite(40px, 104px, 22px, 21px); + chkOverImageRect: sprite(40px, 125px, 22px, 21px); + disImageRect: sprite(18px, 125px, 22px, 21px); + chkDisImageRect: sprite(18px, 125px, 22px, 21px); + + imagePos: point(7px, 12px); +} btnRecordAudio: sprite(379px, 390px, 16px, 24px); btnRecordAudioActive: sprite(379px, 366px, 16px, 24px); recordSignalColor: #f17077; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index f6d5e124d..2f3b5110f 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -153,14 +153,14 @@ void ApiWrap::gotReplyTo(ChannelData *channel, const MTPmessages_Messages &msgs, const MTPDmessages_messages &d(msgs.c_messages_messages()); App::feedUsers(d.vusers); App::feedChats(d.vchats); - App::feedMsgs(d.vmessages, -1); + App::feedMsgs(d.vmessages, NewMessageExisting); } break; case mtpc_messages_messagesSlice: { const MTPDmessages_messagesSlice &d(msgs.c_messages_messagesSlice()); App::feedUsers(d.vusers); App::feedChats(d.vchats); - App::feedMsgs(d.vmessages, -1); + App::feedMsgs(d.vmessages, NewMessageExisting); } break; case mtpc_messages_channelMessages: { @@ -176,7 +176,7 @@ void ApiWrap::gotReplyTo(ChannelData *channel, const MTPmessages_Messages &msgs, App::feedUsers(d.vusers); App::feedChats(d.vchats); - App::feedMsgs(d.vmessages, -1); + App::feedMsgs(d.vmessages, NewMessageExisting); } break; } ReplyToRequests *requests(replyToRequests(channel, true)); @@ -647,7 +647,7 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs MainWidget *m = App::main(); for (QMap::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { - HistoryItem *item = App::histories().addNewMessage(v->at(i.value()), -1); + HistoryItem *item = App::histories().addNewMessage(v->at(i.value()), NewMessageExisting); if (item) { item->initDimensions(); if (m) m->itemResized(item); diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index b0826de09..186edc6b7 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -766,7 +766,7 @@ namespace App { } } - void feedMsgs(const MTPVector &msgs, int msgsState) { + void feedMsgs(const MTPVector &msgs, NewMessageType type) { const QVector &v(msgs.c_vector().v); QMap msgsIds; for (int32 i = 0, l = v.size(); i < l; ++i) { @@ -775,7 +775,7 @@ namespace App { case mtpc_message: { const MTPDmessage &d(msg.c_message()); msgsIds.insert((uint64(uint32(d.vid.v)) << 32) | uint64(i), i); - if (msgsState == 1) { // new message, index my forwarded messages to links overview + if (type == NewMessageUnread) { // new message, index my forwarded messages to links overview checkEntitiesAndViewsUpdate(d); } } break; @@ -784,7 +784,7 @@ namespace App { } } for (QMap::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { - histories().addNewMessage(v.at(i.value()), msgsState); + histories().addNewMessage(v.at(i.value()), type); } } diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index ab3a01c33..afbb0e053 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -103,7 +103,7 @@ namespace App { void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d, bool emitPeerUpdated = true); void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d, bool emitPeerUpdated = true); void checkEntitiesAndViewsUpdate(const MTPDmessage &m); - void feedMsgs(const MTPVector &msgs, int msgsState = 0); // 2 - new read message, 1 - new unread message, 0 - not new message, -1 - searched message + void feedMsgs(const MTPVector &msgs, NewMessageType type); void feedInboxRead(const PeerId &peer, MsgId upTo); void feedOutboxRead(const PeerId &peer, MsgId upTo); void feedWereDeleted(ChannelId channelId, const QVector &msgsIds); diff --git a/Telegram/SourceFiles/art/sprite.png b/Telegram/SourceFiles/art/sprite.png index 281795e88..bfb9e56f0 100644 Binary files a/Telegram/SourceFiles/art/sprite.png and b/Telegram/SourceFiles/art/sprite.png differ diff --git a/Telegram/SourceFiles/art/sprite_200x.png b/Telegram/SourceFiles/art/sprite_200x.png index 18c3d0f4e..0404174c0 100644 Binary files a/Telegram/SourceFiles/art/sprite_200x.png and b/Telegram/SourceFiles/art/sprite_200x.png differ diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index bc1e81ccb..e0368bc2c 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -1623,7 +1623,7 @@ void GroupInfoBox::onNext() { if (_creating == CreatingGroupGroup) { App::wnd()->replaceLayer(new ContactsBox(name, _photoBig)); } else { - _creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(0), MTP_string(name), MTP_string(_description.getLastText().trimmed()), MTP_vector(0)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail)); + _creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(MTPmessages_CreateChannel_flag_broadcast), MTP_string(name), MTP_string(_description.getLastText().trimmed()), MTP_vector(0)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail)); } } @@ -1719,7 +1719,7 @@ SetupChannelBox::SetupChannelBox(ChannelData *channel) : AbstractBox(), _channel(channel), _public(this, qsl("channel_privacy"), 0, lang(lng_create_public_channel_title), true), _private(this, qsl("channel_privacy"), 1, lang(lng_create_private_channel_title)), -_comments(this, lang(lng_create_channel_comments), true), +_comments(this, lang(lng_create_channel_comments), false), _aboutPublicWidth(width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft), _aboutPublic(st::normalFont, lang(lng_create_public_channel_about), _defaultOptions, _aboutPublicWidth), _aboutPrivate(st::normalFont, lang(lng_create_private_channel_about), _defaultOptions, _aboutPublicWidth), @@ -1736,10 +1736,11 @@ a_goodOpacity(0, 0), a_good(animFunc(this, &SetupChannelBox::goodAnimStep)) { _link.setTextMargin(style::margins(st::newGroupLink.textMrg.left() + st::newGroupLink.font->m.width(_linkPlaceholder), st::newGroupLink.textMrg.top(), st::newGroupLink.textMrg.right(), st::newGroupLink.textMrg.bottom())); _aboutPublicHeight = _aboutPublic.countHeight(_aboutPublicWidth); - setMaxHeight(st::newGroupPadding.top() + _public.height() + _aboutPublicHeight + st::newGroupSkip + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth) + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top() + _link.height() + st::newGroupLinkPadding.bottom() + _save.height()); + setMaxHeight(st::newGroupPadding.top() + _public.height() + _aboutPublicHeight + st::newGroupSkip + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth)/* + st::newGroupSkip + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth)*/ + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top() + _link.height() + st::newGroupLinkPadding.bottom() + _save.height()); connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); connect(&_skip, SIGNAL(clicked()), this, SLOT(onClose())); + _comments.hide(); connect(&_link, SIGNAL(changed()), this, SLOT(onChange())); @@ -1753,12 +1754,18 @@ a_goodOpacity(0, 0), a_good(animFunc(this, &SetupChannelBox::goodAnimStep)) { } void SetupChannelBox::hideAll() { + _public.hide(); + _private.hide(); + _comments.hide(); _link.hide(); _save.hide(); _skip.hide(); } void SetupChannelBox::showAll() { + _public.show(); + _private.show(); +// _comments.show(); if (_public.checked()) { _link.show(); } else { @@ -1799,8 +1806,8 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) { QRect aboutPrivate = rtlrect(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _private.y() + _private.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutPublicHeight, width()); _aboutPrivate.draw(p, aboutPrivate.x(), aboutPrivate.y(), aboutPrivate.width()); - QRect aboutComments = rtlrect(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _comments.y() + _comments.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutPublicHeight, width()); - _aboutComments.draw(p, aboutComments.x(), aboutComments.y(), aboutComments.width()); +// QRect aboutComments = rtlrect(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _comments.y() + _comments.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutPublicHeight, width()); +// _aboutComments.draw(p, aboutComments.x(), aboutComments.y(), aboutComments.width()); p.setPen(st::black); p.setFont(st::newGroupLinkFont); @@ -1845,9 +1852,10 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) { void SetupChannelBox::resizeEvent(QResizeEvent *e) { _public.moveToLeft(st::newGroupPadding.left(), st::newGroupPadding.top(), width()); _private.moveToLeft(st::newGroupPadding.left(), _public.y() + _public.height() + _aboutPublicHeight + st::newGroupSkip, width()); - _comments.moveToLeft(st::newGroupPadding.left(), _private.y() + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip, width()); +// _comments.moveToLeft(st::newGroupPadding.left(), _private.y() + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip, width()); - _link.setGeometry(st::newGroupLinkPadding.left(), _comments.y() + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth) + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top(), width() - st::newGroupPadding.left() - st::newGroupPadding.right(), _link.height()); +// _link.setGeometry(st::newGroupLinkPadding.left(), _comments.y() + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth) + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top(), width() - st::newGroupPadding.left() - st::newGroupPadding.right(), _link.height()); + _link.setGeometry(st::newGroupLinkPadding.left(), _private.y() + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top(), width() - st::newGroupPadding.left() - st::newGroupPadding.right(), _link.height()); _invitationLink = QRect(_link.x(), _link.y() + (_link.height() / 2) - st::newGroupLinkFont->height, _link.width(), 2 * st::newGroupLinkFont->height); int32 buttonTop = _link.y() + _link.height() + st::newGroupLinkPadding.bottom(); @@ -1899,8 +1907,8 @@ void SetupChannelBox::closePressed() { void SetupChannelBox::onSave() { if (!_public.checked()) { - if (!_comments.checked()) { - MTP::send(MTPchannels_ToggleComments(_channel->inputChannel, MTP_bool(false))); + if (_comments.checked()) { + MTP::send(MTPchannels_ToggleComments(_channel->inputChannel, MTP_bool(true))); } onClose(); } diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index e4ea84310..6ae8c5540 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -326,6 +326,7 @@ enum { NoUpdatesTimeout = 60 * 1000, // if nothing is received in 1 min we ping NoUpdatesAfterSleepTimeout = 60 * 1000, // if nothing is received in 1 min when was a sleepmode we ping WaitForSkippedTimeout = 1000, // 1s wait for skipped seq or pts in updates + WaitForChannelGetDifference = 1000, // 1s wait after show channel history before sending getChannelDifference MemoryForImageCache = 64 * 1024 * 1024, // after 64mb of unpacked images we try to clear some memory NotifyWindowsCount = 3, // 3 desktop notifies at the same time diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index 0f90816b4..c1b2a9844 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -782,7 +782,9 @@ void DialogsListWidget::dialogsReceived(const QVector &added) { history->asChannelHistory()->unreadCountAll = d.vunread_count.v; history->peer->asChannel()->ptsReceived(d.vpts.v); } - if (d.vtop_message.v > d.vtop_important_message.v) history->setNotLoadedAtBottom(); + if (d.vtop_message.v > d.vtop_important_message.v) { + history->setNotLoadedAtBottom(); + } App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, history); } break; } @@ -823,7 +825,7 @@ void DialogsListWidget::searchReceived(const QVector &messages, bool clearSearchResults(false); } for (QVector::const_iterator i = messages.cbegin(), e = messages.cend(); i != e; ++i) { - HistoryItem *item = App::histories().addNewMessage(*i, -1); + HistoryItem *item = App::histories().addNewMessage(*i, NewMessageExisting); searchResults.push_back(new FakeDialogRow(item)); _lastSearchId = item->id; } @@ -1642,7 +1644,7 @@ void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpReque const MTPDmessages_dialogs &data(dialogs.c_messages_dialogs()); App::feedUsers(data.vusers); App::feedChats(data.vchats); - App::feedMsgs(data.vmessages); + App::feedMsgs(data.vmessages, NewMessageLast); dlgList = &data.vdialogs.c_vector().v; count = dlgList->size(); } break; @@ -1650,7 +1652,7 @@ void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpReque const MTPDmessages_dialogsSlice &data(dialogs.c_messages_dialogsSlice()); App::feedUsers(data.vusers); App::feedChats(data.vchats); - App::feedMsgs(data.vmessages); + App::feedMsgs(data.vmessages, NewMessageLast); dlgList = &data.vdialogs.c_vector().v; count = data.vcount.v; } break; diff --git a/Telegram/SourceFiles/gui/flatcheckbox.cpp b/Telegram/SourceFiles/gui/flatcheckbox.cpp index dee906840..9fbecbea9 100644 --- a/Telegram/SourceFiles/gui/flatcheckbox.cpp +++ b/Telegram/SourceFiles/gui/flatcheckbox.cpp @@ -79,15 +79,17 @@ void FlatCheckbox::paintEvent(QPaintEvent *e) { p.fillRect(rect(), _st.bgColor->b); } - p.setFont(_st.font->f); - p.setRenderHint(QPainter::TextAntialiasing); - p.setPen((_state & StateDisabled ? _st.disColor : _st.textColor)->p); + if (!_text.isEmpty()) { + p.setFont(_st.font->f); + p.setRenderHint(QPainter::TextAntialiasing); + p.setPen((_state & StateDisabled ? _st.disColor : _st.textColor)->p); - QRect tRect(rect()); - tRect.setTop(_st.textTop); - tRect.setLeft(_st.textLeft); -// p.drawText(_st.textLeft, _st.textTop + _st.font->ascent, _text); - p.drawText(tRect, _text, QTextOption(style::al_topleft)); + QRect tRect(rect()); + tRect.setTop(_st.textTop); + tRect.setLeft(_st.textLeft); +// p.drawText(_st.textLeft, _st.textTop + _st.font->ascent, _text); + p.drawText(tRect, _text, QTextOption(style::al_topleft)); + } if (_state & StateDisabled) { QRect sRect(_checked ? _st.chkDisImageRect : _st.disImageRect); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index e87e62260..d9a8be480 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -303,7 +303,6 @@ void FakeDialogRow::paint(Painter &p, int32 w, bool act, bool sel) const { } History::History(const PeerId &peerId) : width(0), height(0) -, msgCount(0) , unreadCount(0) , inboxReadBefore(1) , outboxReadBefore(1) @@ -386,7 +385,7 @@ bool History::updateTyping(uint64 ms, uint32 dots, bool force) { newTypingStr += qsl("..."); } if (typingStr != newTypingStr) { - typingText.setText(st::dlgHistFont, (typingStr = newTypingStr), _textNameOptions); +typingText.setText(st::dlgHistFont, (typingStr = newTypingStr), _textNameOptions); } } if (!typingStr.isEmpty()) { @@ -422,8 +421,7 @@ void History::eraseFromOverview(MediaOverviewType type, MsgId msgId) { ChannelHistory::ChannelHistory(const PeerId &peer) : History(peer), unreadCountAll(0), _onlyImportant(true), -_otherOldLoaded(false), _otherNewLoaded(false), -_otherMsgCount(0), +_otherOldLoaded(false), _otherNewLoaded(true), _collapse(0) { } @@ -453,7 +451,7 @@ bool ChannelHistory::isSwitchReadyFor(MsgId switchId, MsgId &fixInScrollMsgId, i if (itemType == HistoryItemGroup || itemType == HistoryItemCollapse) { if (itemType == HistoryItemGroup && !_onlyImportant) return true; if (itemType == HistoryItemCollapse && _onlyImportant) return true; - bool willNeedCollapse = (itemType == HistoryItemGroup); + bool willNeedCollapse = (itemType == HistoryItemGroup); HistoryItem *prev = findPrevItem(item); if (prev) { @@ -484,18 +482,50 @@ bool ChannelHistory::isSwitchReadyFor(MsgId switchId, MsgId &fixInScrollMsgId, i } return false; } + if (item->history() == this) { + if (_onlyImportant && !item->isImportant()) { + if (_otherList.indexOf(item) >= 0) { + switchMode(); + return true; + } + return false; + } else if (!item->detached()) { + return true; + } + } + } else if (switchId < 0) { + LOG(("App Error: isSwitchReadyFor() switchId not found!")); + switchMode(); + return true; } - LOG(("App Error: isSwitchReadyFor() switchId not found!")); - switchMode(); - return true; + return false; } void ChannelHistory::getSwitchReadyFor(MsgId switchId, MsgId &fixInScrollMsgId, int32 &fixInScrollMsgTop) { if (!isSwitchReadyFor(switchId, fixInScrollMsgId, fixInScrollMsgTop)) { - _otherList.clear(); - _otherNewLoaded = _otherOldLoaded = false; + if (switchId > 0) { + if (HistoryItem *item = App::histItemById(channelId(), switchId)) { + if (_onlyImportant && !item->isImportant()) { + _otherList.clear(); + _otherNewLoaded = _otherOldLoaded = false; - switchMode(); + switchMode(); + } else { + clear(true); + newLoaded = oldLoaded = false; + lastWidth = 0; + } + } else { + clear(true); + newLoaded = oldLoaded = false; + lastWidth = 0; + } + } else { + _otherList.clear(); + _otherNewLoaded = _otherOldLoaded = false; + + switchMode(); + } } } @@ -520,27 +550,94 @@ void ChannelHistory::insertCollapseItem(MsgId wasMinId) { } } +HistoryItem *ChannelHistory::addNewChannelMessage(const MTPMessage &msg, NewMessageType type) { + if (type == NewMessageExisting) return addToHistory(msg); + + HistoryItem *result = addNewToBlocks(msg, type); + if (result) addNewToOther(result, type); + return result; +} + +HistoryItem *ChannelHistory::addNewToBlocks(const MTPMessage &msg, NewMessageType type) { + int32 flags = flagsFromMessage(msg); + bool isImportant = isChannel() ? isImportantChannelMessage(flags) : true; + + if (!loadedAtBottom()) { + HistoryItem *item = addToHistory(msg); + if (item && isImportant) { + setLastMessage(item); + if (type == NewMessageUnread) { + newItemAdded(item); + } + } + return item; + } + + if (!isImportant && onlyImportant()) { + HistoryItem *item = addToHistory(msg), *prev = isEmpty() ? 0 : blocks.back()->items.back(); + HistoryItem *group = addMessageGroupAfterPrev(item, prev); + if (group && group != prev) { + height += group->height(); + } + return item; + } + + if (!isImportant && !onlyImportant() && !isEmpty() && type == NewMessageLast) { + clear(true); + } + + HistoryBlock *to = 0; + bool newBlock = blocks.isEmpty(); + if (newBlock) { + to = new HistoryBlock(this); + } else { + to = blocks.back(); + } + return addNewItem(to, newBlock, createItem(to, msg, (type == NewMessageUnread)), (type == NewMessageUnread)); +} + +void ChannelHistory::addNewToOther(HistoryItem *item, NewMessageType type) { + if (!_otherNewLoaded) return; + + if (!item->isImportant()) { + if (onlyImportant()) { + if (type == NewMessageLast) { + _otherList.clear(); + _otherOldLoaded = false; + } + } else { + if (_otherList.isEmpty() || _otherList.back()->type() != HistoryItemGroup) { + _otherList.push_back(regItem(new HistoryGroup(this, 0, item, _otherList.isEmpty() ? item->date : _otherList.back()->date))); + } else { + static_cast(_otherList.back())->uniteWith(item); + } + return; + } + } + _otherList.push_back(item); +} + void ChannelHistory::switchMode() { OtherList savedList; - savedList.reserve(msgCount); - for (Blocks::const_iterator i = blocks.cbegin(), e = blocks.cend(); i != e; ++i) { - HistoryBlock *block = *i; - for (HistoryBlock::Items::const_iterator j = block->items.cbegin(), end = block->items.cend(); j != end; ++j) { - HistoryItem *item = *j; - HistoryItemType itemType = item->type(); - if (itemType == HistoryItemMsg || itemType == HistoryItemGroup) { - savedList.push_back(item); + if (!blocks.isEmpty()) { + savedList.reserve(((blocks.size() - 2) * MessagesPerPage + blocks.back()->items.size()) * (onlyImportant() ? 2 : 1)); + for (Blocks::const_iterator i = blocks.cbegin(), e = blocks.cend(); i != e; ++i) { + HistoryBlock *block = *i; + for (HistoryBlock::Items::const_iterator j = block->items.cbegin(), end = block->items.cend(); j != end; ++j) { + HistoryItem *item = *j; + HistoryItemType itemType = item->type(); + if (itemType == HistoryItemMsg || itemType == HistoryItemGroup) { + savedList.push_back(item); + } } } } - int32 savedMsgCount = msgCount; bool savedNewLoaded = newLoaded, savedOldLoaded = oldLoaded; clear(true); newLoaded = _otherNewLoaded; oldLoaded = _otherOldLoaded; - msgCount = _otherMsgCount; if (int32 count = _otherList.size()) { blocks.reserve(qCeil(count / float64(MessagesPerPage)) + 1); createInitialDateBlock(_otherList.front()->date); @@ -564,7 +661,6 @@ void ChannelHistory::switchMode() { _otherList = savedList; _otherNewLoaded = savedNewLoaded; _otherOldLoaded = savedOldLoaded; - _otherMsgCount = savedMsgCount; _onlyImportant = !_onlyImportant; @@ -909,30 +1005,15 @@ void Histories::remove(const PeerId &peer) { } } -HistoryItem *Histories::addNewMessage(const MTPmessage &msg, int msgState) { +HistoryItem *Histories::addNewMessage(const MTPmessage &msg, NewMessageType type) { int32 flags = 0; - PeerId peer = peerFromMessage(msg, &flags); + PeerId peer = peerFromMessage(msg); if (!peer) return 0; - History *h = findOrInsert(peer, 0, 0); - bool isImportant = h->isChannel() ? isImportantChannelMessage(flags) : true; - if (msgState < 0 || (!isImportant && h->asChannelHistory()->onlyImportant())) { - return h->addToHistory(msg); - } - if (!h->loadedAtBottom()) { - HistoryItem *item = h->addToHistory(msg); - if (item && isImportant) { - h->setLastMessage(item); - if (msgState > 0) { - h->newItemAdded(item); - } - } - return item; - } - return h->addNewMessage(msg, msgState > 0); + return findOrInsert(peer, 0, 0)->addNewMessage(msg, type); } -HistoryItem *History::createItem(HistoryBlock *block, const MTPmessage &msg, bool newMsg, bool returnExisting) { +HistoryItem *History::createItem(HistoryBlock *block, const MTPmessage &msg, bool applyServiceAction, bool returnExisting) { HistoryItem *result = 0; MsgId msgId = 0; @@ -1046,7 +1127,7 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPmessage &msg, boo const MTPDmessageService &d(msg.c_messageService()); result = new HistoryServiceMsg(this, block, d); - if (newMsg) { + if (applyServiceAction) { const MTPmessageAction &action(d.vaction); switch (d.vaction.type()) { case mtpc_messageActionChatAddUser: { @@ -1146,7 +1227,21 @@ HistoryItem *History::addNewService(MsgId msgId, QDateTime date, const QString & return addNewItem(to, newBlock, regItem(new HistoryServiceMsg(this, to, msgId, date, text, flags, media)), newMsg); } -HistoryItem *History::addNewMessage(const MTPmessage &msg, bool newMsg) { +HistoryItem *History::addNewMessage(const MTPmessage &msg, NewMessageType type) { + if (isChannel()) return asChannelHistory()->addNewChannelMessage(msg, type); + + if (type == NewMessageExisting) return addToHistory(msg); + if (!loadedAtBottom()) { + HistoryItem *item = addToHistory(msg); + if (item) { + setLastMessage(item); + if (type == NewMessageUnread) { + newItemAdded(item); + } + } + return item; + } + HistoryBlock *to = 0; bool newBlock = blocks.isEmpty(); if (newBlock) { @@ -1154,7 +1249,7 @@ HistoryItem *History::addNewMessage(const MTPmessage &msg, bool newMsg) { } else { to = blocks.back(); } - return addNewItem(to, newBlock, createItem(to, msg, newMsg), newMsg); + return addNewItem(to, newBlock, createItem(to, msg, (type == NewMessageUnread)), (type == NewMessageUnread)); } HistoryItem *History::addToHistory(const MTPmessage &msg) { @@ -1246,7 +1341,6 @@ HistoryItem *History::addNewItem(HistoryBlock *to, bool newBlock, HistoryItem *a to->height += dh; height += dh; } - setMsgCount(msgCount + 1); if (newMsg) { newItemAdded(adding); } @@ -1356,12 +1450,30 @@ HistoryItem *History::addItemAfterPrevToBlock(HistoryItem *item, HistoryItem *pr return item; } -HistoryItem *History::addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, const QDateTime &date, HistoryItem *prev, HistoryBlock *block) { +HistoryItem *History::addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, HistoryItem *prev, HistoryBlock *block) { if (prev && prev->type() == HistoryItemGroup) { static_cast(prev)->uniteWith(group.vmin_id.v, group.vmax_id.v, group.vcount.v); return prev; } - return addItemAfterPrevToBlock(regItem(new HistoryGroup(this, block, group, date)), prev, block); + return addItemAfterPrevToBlock(regItem(new HistoryGroup(this, block, group, prev ? prev->date : date(group.vdate))), prev, block); +} + +HistoryItem *History::addMessageGroupAfterPrev(HistoryItem *newItem, HistoryItem *prev) { + if (prev && prev->type() == HistoryItemGroup) { + static_cast(prev)->uniteWith(newItem); + return prev; + } + + QDateTime date = prev ? prev->date : newItem->date; + HistoryBlock *block = prev->block(); + if (!block) { + createInitialDateBlock(date); + + block = new HistoryBlock(this); + block->y = height; + blocks.push_back(block); + } + return addItemAfterPrevToBlock(regItem(new HistoryGroup(this, block, newItem, date)), prev, block); } void History::addOlderSlice(const QVector &slice, const QVector *collapsed) { @@ -1393,17 +1505,16 @@ void History::addOlderSlice(const QVector &slice, const QVectorc_messageGroup()); if (group.vmin_id.v >= adding->id) break; - prev = addMessageGroupAfterPrevToBlock(group, (prev ? prev : adding)->date, prev, block); + prev = addMessageGroupAfterPrevToBlock(group, prev, block); } prev = addItemAfterPrevToBlock(adding, prev, block); - setMsgCount(msgCount + 1); } for (; groupsIt != groupsEnd; ++groupsIt) { if (groupsIt->type() != mtpc_messageGroup) continue; const MTPDmessageGroup &group(groupsIt->c_messageGroup()); - prev = addMessageGroupAfterPrevToBlock(group, prev ? prev->date : date(group.vdate), prev, block); + prev = addMessageGroupAfterPrevToBlock(group, prev, block); } while (till && prev && till->type() == HistoryItemGroup && prev->type() == HistoryItemGroup) { @@ -1551,17 +1662,16 @@ void History::addNewerSlice(const QVector &slice, const QVectorc_messageGroup()); if (group.vmin_id.v >= adding->id) break; - prev = addMessageGroupAfterPrevToBlock(group, (prev ? prev : adding)->date, prev, block); + prev = addMessageGroupAfterPrevToBlock(group, prev, block); } prev = addItemAfterPrevToBlock(adding, prev, block); - setMsgCount(msgCount + 1); } for (; groupsIt != groupsEnd; ++groupsIt) { if (groupsIt->type() != mtpc_messageGroup) continue; const MTPDmessageGroup &group(groupsIt->c_messageGroup()); - prev = addMessageGroupAfterPrevToBlock(group, prev ? prev->date : date(group.vdate), prev, block); + prev = addMessageGroupAfterPrevToBlock(group, prev, block); } bool wasLoadedAtBottom = loadedAtBottom(); @@ -1705,10 +1815,25 @@ MsgId History::outboxRead(HistoryItem *wasRead) { return outboxRead(wasRead ? wasRead->id : 0); } +HistoryItem *History::lastImportantMessage() const { + if (isEmpty()) return 0; + bool channel = isChannel(); + for (int32 blockIndex = blocks.size(); blockIndex > 0;) { + HistoryBlock *block = blocks.at(--blockIndex); + for (int32 itemIndex = block->items.size(); itemIndex > 0;) { + HistoryItem *item = block->items.at(--itemIndex); + if (channel ? item->isImportant() : (item->type() == HistoryItemMsg)) { + return item; + } + } + } + return 0; +} + void History::setUnreadCount(int32 newUnreadCount, bool psUpdate) { if (unreadCount != newUnreadCount) { if (newUnreadCount == 1) { - if (loadedAtBottom()) showFrom = isEmpty() ? 0 : blocks.back()->items.back(); + if (loadedAtBottom()) showFrom = lastImportantMessage(); inboxReadBefore = qMax(inboxReadBefore, msgIdForRead()); } else if (!newUnreadCount) { showFrom = 0; @@ -1722,12 +1847,6 @@ void History::setUnreadCount(int32 newUnreadCount, bool psUpdate) { } } -void History::setMsgCount(int32 newMsgCount) { - if (msgCount != newMsgCount) { - msgCount = newMsgCount; - } -} - void History::setMute(bool newMute) { if (mute != newMute) { App::histories().unreadMuted += newMute ? unreadCount : (-unreadCount); @@ -1813,7 +1932,7 @@ bool History::loadedAtTop() const { } bool History::isReadyFor(MsgId msgId, MsgId &fixInScrollMsgId, int32 &fixInScrollMsgTop) { - if (msgId != ShowAtTheEndMsgId && msgId != ShowAtUnreadMsgId && msgId < 0 && isChannel()) { + if (msgId != ShowAtTheEndMsgId && msgId != ShowAtUnreadMsgId && isChannel()) { return asChannelHistory()->isSwitchReadyFor(msgId, fixInScrollMsgId, fixInScrollMsgTop); } fixInScrollMsgId = 0; @@ -1835,7 +1954,7 @@ bool History::isReadyFor(MsgId msgId, MsgId &fixInScrollMsgId, int32 &fixInScrol } void History::getReadyFor(MsgId msgId, MsgId &fixInScrollMsgId, int32 &fixInScrollMsgTop) { - if (msgId != ShowAtTheEndMsgId && msgId != ShowAtUnreadMsgId && msgId < 0 && isChannel()) { + if (msgId != ShowAtTheEndMsgId && msgId != ShowAtUnreadMsgId && isChannel()) { return asChannelHistory()->getSwitchReadyFor(msgId, fixInScrollMsgId, fixInScrollMsgTop); } if (!isReadyFor(msgId, fixInScrollMsgId, fixInScrollMsgTop)) { @@ -1877,14 +1996,7 @@ void History::setPosInDialogsDate(const QDateTime &date) { } void History::fixLastMessage(bool wasAtBottom) { - if (wasAtBottom && isEmpty()) { - wasAtBottom = false; - } - if (wasAtBottom) { - setLastMessage(blocks.back()->items.back(), false); - } else { - setLastMessage(0); - } + setLastMessage(wasAtBottom ? lastImportantMessage() : 0, false); } MsgId History::minMsgId() const { @@ -1977,7 +2089,6 @@ void History::clear(bool leaveItems) { delete *i; } blocks.clear(); - setMsgCount(0); if (leaveItems) { lastKeyboardInited = false; } else { @@ -2173,9 +2284,7 @@ void HistoryBlock::removeItem(HistoryItem *item) { history->setUnreadCount(history->unreadCount - 1); } int32 itemType = item->type(); - if (itemType == HistoryItemMsg) { - history->setMsgCount(history->msgCount - 1); - } else if (itemType == HistoryItemUnreadBar) { + if (itemType == HistoryItemUnreadBar) { if (history->unreadBar == item) { history->unreadBar = 0; } @@ -5616,7 +5725,7 @@ HistoryItem(history, block, msgId, flags, date, from) } void HistoryMessage::initTime() { - _timeText = date.toString(cTimeFormat()) + qsl(" (%1)").arg(id); + _timeText = date.toString(cTimeFormat());// + qsl(" (%1)").arg(id); _timeWidth = st::msgDateFont->m.width(_timeText); _viewsText = (_views >= 0) ? QString::number(_views ? _views : 1) : QString(); @@ -5928,14 +6037,14 @@ void HistoryMessage::draw(Painter &p, uint32 selection) const { fromNameUpdated(); _fromVersion = _from->nameVersion; } - int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.right()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; + int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.left()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; if (justMedia()) { if (_media->maxWidth() > mwidth) mwidth = _media->maxWidth(); if (_media->currentWidth() < mwidth) mwidth = _media->currentWidth(); } if (width > mwidth) { if (fromChannel()) { - left += (width - mwidth) / 2; +// left += (width - mwidth) / 2; } else if (out()) { left += width - mwidth; } @@ -5951,7 +6060,7 @@ void HistoryMessage::draw(Painter &p, uint32 selection) const { if (width >= _maxw) { if (fromChannel()) { - left += (width - _maxw) / 2; +// left += (width - _maxw) / 2; } else if (out()) { left += width - _maxw; } @@ -6037,14 +6146,14 @@ int32 HistoryMessage::resize(int32 width) { } bool HistoryMessage::hasPoint(int32 x, int32 y) const { - int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.right()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; + int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.left()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; if (justMedia()) { if (_media->maxWidth() > mwidth) mwidth = _media->maxWidth(); if (_media->currentWidth() < mwidth) mwidth = _media->currentWidth(); } if (width > mwidth) { if (fromChannel()) { - left += (width - mwidth) / 2; +// left += (width - mwidth) / 2; } else if (out()) { left += width - mwidth; } @@ -6058,7 +6167,7 @@ bool HistoryMessage::hasPoint(int32 x, int32 y) const { if (width >= _maxw) { if (fromChannel()) { - left += (width - _maxw) / 2; +// left += (width - _maxw) / 2; } else if (out()) { left += width - _maxw; } @@ -6092,14 +6201,14 @@ void HistoryMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 state = HistoryDefaultCursorState; lnk = TextLinkPtr(); - int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.right()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; + int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.left()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; if (justMedia()) { if (_media->maxWidth() > mwidth) mwidth = _media->maxWidth(); if (_media->currentWidth() < mwidth) mwidth = _media->currentWidth(); } if (width > mwidth) { if (fromChannel()) { - left += (width - mwidth) / 2; +// left += (width - mwidth) / 2; } else if (out()) { left += width - mwidth; } @@ -6118,7 +6227,7 @@ void HistoryMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 if (width >= _maxw) { if (fromChannel()) { - left += (width - _maxw) / 2; +// left += (width - _maxw) / 2; } else if (out()) { left += width - _maxw; } @@ -6171,10 +6280,10 @@ void HistoryMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, upon = false; if (justMedia()) return; - int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.right()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; + int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.left()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; if (width > mwidth) { if (fromChannel()) { - left += (width - mwidth) / 2; +// left += (width - mwidth) / 2; } else if (out()) { left += width - mwidth; } @@ -6189,7 +6298,7 @@ void HistoryMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, if (width >= _maxw) { if (fromChannel()) { - left += (width - _maxw) / 2; +// left += (width - _maxw) / 2; } else if (out()) { left += width - _maxw; } @@ -6328,10 +6437,10 @@ int32 HistoryForwarded::resize(int32 width) { bool HistoryForwarded::hasPoint(int32 x, int32 y) const { if (!justMedia()) { - int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.right()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; + int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.left()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; if (width > mwidth) { if (fromChannel()) { - left += (width - mwidth) / 2; +//f left += (width - mwidth) / 2; } else if (out()) { left += width - mwidth; } @@ -6346,7 +6455,7 @@ bool HistoryForwarded::hasPoint(int32 x, int32 y) const { if (width >= _maxw) { if (fromChannel()) { - left += (width - _maxw) / 2; +// left += (width - _maxw) / 2; } else if (out()) { left += width - _maxw; } @@ -6363,10 +6472,10 @@ void HistoryForwarded::getState(TextLinkPtr &lnk, HistoryCursorState &state, int state = HistoryDefaultCursorState; if (!justMedia()) { - int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.right()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; + int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.left()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; if (width > mwidth) { if (fromChannel()) { - left += (width - mwidth) / 2; +// left += (width - mwidth) / 2; } else if (out()) { left += width - mwidth; } @@ -6384,7 +6493,7 @@ void HistoryForwarded::getState(TextLinkPtr &lnk, HistoryCursorState &state, int if (width >= _maxw) { if (fromChannel()) { - left += (width - _maxw) / 2; +// left += (width - _maxw) / 2; } else if (out()) { left += width - _maxw; } @@ -6429,10 +6538,10 @@ void HistoryForwarded::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 upon = false; if (!justMedia()) { - int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.right()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; + int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.left()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; if (width > mwidth) { if (fromChannel()) { - left += (width - mwidth) / 2; +// left += (width - mwidth) / 2; } else if (out()) { left += width - mwidth; } @@ -6447,7 +6556,7 @@ void HistoryForwarded::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 if (width >= _maxw) { if (fromChannel()) { - left += (width - _maxw) / 2; +// left += (width - _maxw) / 2; } else if (out()) { left += width - _maxw; } @@ -6655,10 +6764,10 @@ int32 HistoryReply::resize(int32 width) { bool HistoryReply::hasPoint(int32 x, int32 y) const { if (!justMedia()) { - int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.right()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; + int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.left()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; if (width > mwidth) { if (fromChannel()) { - left += (width - mwidth) / 2; +// left += (width - mwidth) / 2; } else if (out()) { left += width - mwidth; } @@ -6673,7 +6782,7 @@ bool HistoryReply::hasPoint(int32 x, int32 y) const { if (width >= _maxw) { if (fromChannel()) { - left += (width - _maxw) / 2; +// left += (width - _maxw) / 2; } else if (out()) { left += width - _maxw; } @@ -6690,10 +6799,10 @@ void HistoryReply::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x state = HistoryDefaultCursorState; if (!justMedia()) { - int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.right()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; + int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.left()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; if (width > mwidth) { if (fromChannel()) { - left += (width - mwidth) / 2; +// left += (width - mwidth) / 2; } else if (out()) { left += width - mwidth; } @@ -6711,7 +6820,7 @@ void HistoryReply::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x if (width >= _maxw) { if (fromChannel()) { - left += (width - _maxw) / 2; +// left += (width - _maxw) / 2; } else if (out()) { left += width - _maxw; } @@ -6753,10 +6862,10 @@ void HistoryReply::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, i upon = false; if (!justMedia()) { - int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.right()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; + int32 left = fromChannel() ? (st::msgMargin.left() + st::msgMargin.left()) / 2 : (out() ? st::msgMargin.right() : st::msgMargin.left()), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth; if (width > mwidth) { if (fromChannel()) { - left += (width - mwidth) / 2; +// left += (width - mwidth) / 2; } else if (out()) { left += width - mwidth; } @@ -6771,7 +6880,7 @@ void HistoryReply::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, i if (width >= _maxw) { if (fromChannel()) { - left += (width - _maxw) / 2; +// left += (width - _maxw) / 2; } else if (out()) { left += width - _maxw; } @@ -7075,10 +7184,15 @@ HistoryItem *createDayServiceMsg(History *history, HistoryBlock *block, QDateTim } HistoryGroup::HistoryGroup(History *history, HistoryBlock *block, const MTPDmessageGroup &group, const QDateTime &date) : -HistoryServiceMsg(history, block, clientMsgId(), date, lng_channel_comments_count(lt_count, group.vcount.v) + qsl(" (%1 .. %2)").arg(group.vmin_id.v).arg(group.vmax_id.v)), +HistoryServiceMsg(history, block, clientMsgId(), date, lng_channel_comments_count(lt_count, group.vcount.v)/* + qsl(" (%1 .. %2)").arg(group.vmin_id.v).arg(group.vmax_id.v)*/), _minId(group.vmin_id.v), _maxId(group.vmax_id.v), _count(group.vcount.v), _lnk(new CommentsLink(this)) { } +HistoryGroup::HistoryGroup(History *history, HistoryBlock *block, HistoryItem *newItem, const QDateTime &date) : +HistoryServiceMsg(history, block, clientMsgId(), date, lng_channel_comments_count(lt_count, 1)/* + qsl(" (%1 .. %2)").arg(newItem->id - 1).arg(newItem->id + 1)*/), +_minId(newItem->id - 1), _maxId(newItem->id + 1), _count(1), _lnk(new CommentsLink(this)) { +} + void HistoryGroup::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const { lnk = TextLinkPtr(); state = HistoryDefaultCursorState; @@ -7100,20 +7214,20 @@ void HistoryGroup::uniteWith(MsgId minId, MsgId maxId, int32 count) { if (minId == _minId && maxId == _maxId && count == _count) return; if (minId < _minId) { - if (maxId <= _minId) { + if (maxId <= _minId + 1) { _count += count; } else if (maxId <= _maxId) { // :( smth not precise - _count += qMax(0, count - (maxId - _minId)); + _count += qMax(0, count - (maxId - _minId - 1)); } else { // :( smth not precise _count = qMax(count, _count); _maxId = maxId; } _minId = minId; } else if (maxId > _maxId) { - if (minId >= _maxId) { + if (minId + 1 >= _maxId) { _count += count; } else if (minId >= _minId) { // :( smth not precise - _count += qMax(0, count - (_maxId - minId)); + _count += qMax(0, count - (_maxId - minId - 1)); } else { // :( smth not precise _count = qMax(count, _count); _minId = minId; @@ -7135,7 +7249,7 @@ bool HistoryGroup::decrementCount() { } void HistoryGroup::updateText() { - setText(lng_channel_comments_count(lt_count, _count) + qsl(" (%1 .. %2)").arg(_minId).arg(_maxId)); + setText(lng_channel_comments_count(lt_count, _count)/* + qsl(" (%1 .. %2)").arg(_minId).arg(_maxId)*/); } HistoryCollapse::HistoryCollapse(History *history, HistoryBlock *block, MsgId wasMinId, const QDateTime &date) : diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 478ee9658..f6f968f63 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -34,6 +34,12 @@ extern TextParseOptions _textNameOptions, _textDlgOptions, _historyTextOptions, #include "structs.h" +enum NewMessageType { + NewMessageUnread, + NewMessageLast, + NewMessageExisting, +}; + class History; class Histories : public Animated { public: @@ -56,7 +62,7 @@ public: unreadFull = unreadMuted = 0; } - HistoryItem *addNewMessage(const MTPmessage &msg, int msgState = 1); // 2 - new read message, 1 - new unread message, 0 - not new message, -1 - searched message + HistoryItem *addNewMessage(const MTPmessage &msg, NewMessageType type); // HistoryItem *addToBack(const MTPgeoChatMessage &msg, bool newMsg = true); typedef QMap TypingHistories; // when typing in this history started @@ -187,12 +193,12 @@ public: clear(); } - HistoryItem *createItem(HistoryBlock *block, const MTPmessage &msg, bool newMsg, bool returnExisting = false); + HistoryItem *createItem(HistoryBlock *block, const MTPmessage &msg, bool applyServiceAction, bool returnExisting = false); HistoryItem *createItemForwarded(HistoryBlock *block, MsgId id, QDateTime date, int32 from, HistoryMessage *msg); HistoryItem *createItemDocument(HistoryBlock *block, MsgId id, int32 flags, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc); HistoryItem *addNewService(MsgId msgId, QDateTime date, const QString &text, int32 flags = 0, HistoryMedia *media = 0, bool newMsg = true); - HistoryItem *addNewMessage(const MTPmessage &msg, bool newMsg = true); + HistoryItem *addNewMessage(const MTPmessage &msg, NewMessageType type); HistoryItem *addToHistory(const MTPmessage &msg); HistoryItem *addNewForwarded(MsgId id, QDateTime date, int32 from, HistoryMessage *item); HistoryItem *addNewDocument(MsgId id, int32 flags, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc); @@ -212,8 +218,9 @@ public: MsgId outboxRead(MsgId upTo); MsgId outboxRead(HistoryItem *wasRead); + HistoryItem *lastImportantMessage() const; + void setUnreadCount(int32 newUnreadCount, bool psUpdate = true); - void setMsgCount(int32 newMsgCount); void setMute(bool newMute); void getNextShowFrom(HistoryBlock *block, int32 i); void addUnreadBar(); @@ -334,16 +341,15 @@ public: private: - HistoryItem *addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, const QDateTime &date, HistoryItem *prev, HistoryBlock *block); - HistoryItem *addNewItem(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg); - -protected: + friend class HistoryBlock; + friend class ChannelHistory; void createInitialDateBlock(const QDateTime &date); HistoryItem *addItemAfterPrevToBlock(HistoryItem *item, HistoryItem *prev, HistoryBlock *block); HistoryItem *addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex); - - friend class HistoryBlock; + HistoryItem *addNewItem(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg); + HistoryItem *addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, HistoryItem *prev, HistoryBlock *block); + HistoryItem *addMessageGroupAfterPrev(HistoryItem *newItem, HistoryItem *prev); }; @@ -372,8 +378,19 @@ public: return _collapse; } + void clearOther() { + _otherNewLoaded = true; + _otherOldLoaded = false; + _otherList.clear(); + } + private: + friend class History; + HistoryItem* addNewChannelMessage(const MTPMessage &msg, NewMessageType type); + HistoryItem *addNewToBlocks(const MTPMessage &msg, NewMessageType type); + void addNewToOther(HistoryItem *item, NewMessageType type); + HistoryGroup *findGroup(MsgId msgId) const; HistoryBlock *findGroupBlock(MsgId msgId) const; HistoryGroup *findGroupInOther(MsgId msgId) const; @@ -383,7 +400,6 @@ private: typedef QList OtherList; OtherList _otherList; bool _otherOldLoaded, _otherNewLoaded; - int32 _otherMsgCount; HistoryCollapse *_collapse; @@ -740,8 +756,8 @@ enum InfoDisplayType { }; inline bool isImportantChannelMessage(int32 flags) { - /*(flags & MTPDmessage_flag_out) || (flags & MTPDmessage_flag_notify_by_from) || */ - return !(flags & MTPDmessage::flag_from_id) && (flags != 0); // always has_from_id || has_views + /**/ + return (flags & MTPDmessage_flag_out) || (flags & MTPDmessage_flag_notify_by_from) || (!(flags & MTPDmessage::flag_from_id) && (flags != 0)); // always has_from_id || has_views } enum HistoryItemType { @@ -1729,6 +1745,7 @@ class HistoryGroup : public HistoryServiceMsg { public: HistoryGroup(History *history, HistoryBlock *block, const MTPDmessageGroup &group, const QDateTime &date); + HistoryGroup(History *history, HistoryBlock *block, HistoryItem *newItem, const QDateTime &date); void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const; void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { symbol = 0xFFFF; @@ -1742,7 +1759,10 @@ public: return HistoryItemGroup; } void uniteWith(MsgId minId, MsgId maxId, int32 count); - void uniteWith(const HistoryGroup *other) { + void uniteWith(HistoryItem *item) { + uniteWith(item->id - 1, item->id + 1, 1); + } + void uniteWith(HistoryGroup *other) { uniteWith(other->_minId, other->_maxId, other->_count); } diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 346a4b536..8187df46e 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -750,6 +750,10 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { dragActionUpdate(e->globalPos()); } + int32 selectedForForward, selectedForDelete; + getSelectionState(selectedForForward, selectedForDelete); + bool canSendMessages = historyWidget->canSendMessages(hist->peer); + // -2 - has full selected items, but not over, -1 - has selection, but no over, 0 - no selection, 1 - over text, 2 - over full selected items int32 isUponSelected = 0, hasSelected = 0;; if (!_selected.isEmpty()) { @@ -789,7 +793,7 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (isUponSelected > 0) { _menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true); } - if (item && item->id > 0 && isUponSelected != 2 && isUponSelected != -2 && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) { + if (item && item->id > 0 && isUponSelected != 2 && isUponSelected != -2 && canSendMessages) { _menu->addAction(lang(lng_context_reply_msg), historyWidget, SLOT(onReplyToMessage())); } if (lnkPhoto) { @@ -809,7 +813,7 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } if (isUponSelected > 1) { _menu->addAction(lang(lng_context_forward_selected), historyWidget, SLOT(onForwardSelected())); - if ((!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) { + if (selectedForDelete == selectedForForward) { _menu->addAction(lang(lng_context_delete_selected), historyWidget, SLOT(onDeleteSelected())); } _menu->addAction(lang(lng_context_clear_selection), historyWidget, SLOT(onClearSelected())); @@ -822,7 +826,7 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { _menu->addAction(lang(lng_context_delete_msg), historyWidget, SLOT(deleteMessage()))->setEnabled(true); } } - if (App::hoveredLinkItem()->id > 0 && !App::hoveredLinkItem()->serviceMsg() && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) { + if (App::hoveredLinkItem()->id > 0 && !App::hoveredLinkItem()->serviceMsg()) { _menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true); } App::contextItem(App::hoveredLinkItem()); @@ -837,11 +841,11 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (isUponSelected > 0) { if (!_menu) _menu = new ContextMenu(this); _menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true); - if (item && item->id > 0 && isUponSelected != 2 && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) { + if (item && item->id > 0 && isUponSelected != 2 && canSendMessages) { _menu->addAction(lang(lng_context_reply_msg), historyWidget, SLOT(onReplyToMessage())); } } else { - if (item && item->id > 0 && isUponSelected != -2 && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) { + if (item && item->id > 0 && isUponSelected != -2 && canSendMessages) { if (!_menu) _menu = new ContextMenu(this); _menu->addAction(lang(lng_context_reply_msg), historyWidget, SLOT(onReplyToMessage())); } @@ -882,7 +886,7 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (isUponSelected > 1) { if (!_menu) _menu = new ContextMenu(this); _menu->addAction(lang(lng_context_forward_selected), historyWidget, SLOT(onForwardSelected())); - if ((!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) { + if (selectedForDelete == selectedForForward) { _menu->addAction(lang(lng_context_delete_selected), historyWidget, SLOT(onDeleteSelected())); } _menu->addAction(lang(lng_context_clear_selection), historyWidget, SLOT(onClearSelected())); @@ -897,11 +901,11 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { _menu->addAction(lang((msg && msg->uploading()) ? lng_context_cancel_upload : lng_context_delete_msg), historyWidget, SLOT(deleteMessage()))->setEnabled(true); } } - if (item->id > 0 && !item->serviceMsg() && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) { + if (item->id > 0 && !item->serviceMsg()) { _menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true); } } else { - if (App::mousedItem() && !App::mousedItem()->serviceMsg() && App::mousedItem()->id > 0 && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) { + if (App::mousedItem() && !App::mousedItem()->serviceMsg() && App::mousedItem()->id > 0) { if (!_menu) _menu = new ContextMenu(this); _menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true); item = App::mousedItem(); @@ -1065,7 +1069,11 @@ void HistoryList::keyPressEvent(QKeyEvent *e) { } else if (e == QKeySequence::Copy && !_selected.isEmpty()) { copySelectedText(); } else if (e == QKeySequence::Delete) { - historyWidget->onDeleteSelected(); + int32 selectedForForward, selectedForDelete; + getSelectionState(selectedForForward, selectedForDelete); + if (!_selected.isEmpty() && selectedForDelete == selectedForForward) { + historyWidget->onDeleteSelected(); + } } else { e->ignore(); } @@ -1304,17 +1312,22 @@ bool HistoryList::canCopySelected() const { } bool HistoryList::canDeleteSelected() const { - return !_selected.isEmpty() && (_selected.cbegin().value() == FullItemSel) && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned); + if (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel) return false; + int32 selectedForForward, selectedForDelete; + getSelectionState(selectedForForward, selectedForDelete); + return (selectedForForward == selectedForDelete); } void HistoryList::getSelectionState(int32 &selectedForForward, int32 &selectedForDelete) const { selectedForForward = selectedForDelete = 0; for (SelectedItems::const_iterator i = _selected.cbegin(), e = _selected.cend(); i != e; ++i) { if (i.key()->type() == HistoryItemMsg && i.value() == FullItemSel) { - ++selectedForDelete; - if (!i.key()->serviceMsg() && i.key()->id > 0) { - ++selectedForForward; + if (!hist || !hist->peer || !hist->peer->isChannel() || hist->peer->asChannel()->adminned) { + ++selectedForDelete; + } else if (i.key()->out()) { + ++selectedForDelete; } + ++selectedForForward; } } if (!selectedForDelete && !selectedForForward && !_selected.isEmpty()) { // text selection @@ -2316,6 +2329,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) , _kbShow(this, st::btnBotKbShow) , _kbHide(this, st::btnBotKbHide) , _cmdStart(this, st::btnBotCmdStart) +, _broadcast(this, QString(), true, st::broadcastToggle) , _cmdStartShown(false) , _field(this, st::taMsgField, lang(lng_message_ph)) , _recordAnim(animFunc(this, &HistoryWidget::recordStep)) @@ -2422,7 +2436,6 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) _field.setCtrlEnterSubmit(cCtrlEnter()); _field.hide(); - _field.resize(width() - _send.width() - _attachDocument.width() - _attachEmoji.width(), _send.height() - 2 * st::sendPadding); _send.hide(); _unblock.hide(); _botStart.hide(); @@ -2435,6 +2448,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) _attachEmoji.hide(); _kbShow.hide(); _kbHide.hide(); + _broadcast.hide(); _cmdStart.hide(); _attachDocument.installEventFilter(&_attachType); @@ -2992,8 +3006,8 @@ void HistoryWidget::showPeerHistory(const PeerId &peerId, MsgId showAtMsgId) { if (_replyToId) { updateReplyTo(); if (!_replyTo) App::api()->requestReplyTo(0, _peer->asChannel(), _replyToId); - resizeEvent(0); } + resizeEvent(0); if (!_previewCancelled) { onPreviewParse(); } @@ -3114,6 +3128,7 @@ void HistoryWidget::updateControlsVisibility() { _attachDocument.hide(); _attachPhoto.hide(); _attachEmoji.hide(); + _broadcast.hide(); _toHistoryEnd.hide(); _collapseComments.hide(); _kbShow.hide(); @@ -3152,6 +3167,7 @@ void HistoryWidget::updateControlsVisibility() { _cmdStart.hide(); _attachDocument.hide(); _attachPhoto.hide(); + _broadcast.hide(); _kbScroll.hide(); _replyForwardPreviewCancel.hide(); } else if (isBotStart()) { @@ -3169,6 +3185,7 @@ void HistoryWidget::updateControlsVisibility() { _cmdStart.hide(); _attachDocument.hide(); _attachPhoto.hide(); + _broadcast.hide(); _kbScroll.hide(); _replyForwardPreviewCancel.hide(); } else { @@ -3193,6 +3210,7 @@ void HistoryWidget::updateControlsVisibility() { _cmdStart.hide(); _attachDocument.hide(); _attachPhoto.hide(); + _broadcast.hide(); if (_kbShown) { _kbScroll.show(); } else { @@ -3235,6 +3253,11 @@ void HistoryWidget::updateControlsVisibility() { _attachDocument.show(); _attachPhoto.hide(); } + if (hasBroadcastToggle()) { + _broadcast.show(); + } else { + _broadcast.hide(); + } } if (_replyToId || readyToForward() || (_previewData && _previewData->pendingTill >= 0) || _kbReplyTo) { if (_replyForwardPreviewCancel.isHidden()) { @@ -3253,6 +3276,7 @@ void HistoryWidget::updateControlsVisibility() { _botStart.hide(); _attachDocument.hide(); _attachPhoto.hide(); + _broadcast.hide(); _kbScroll.hide(); _replyForwardPreviewCancel.hide(); _attachDocument.hide(); @@ -3561,6 +3585,11 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { } else if (_delayedShowAtMsgId > 0) { offset = -loadCount / 2; from = _delayedShowAtMsgId; + if (HistoryItem *item = App::histItemById(_channel, _delayedShowAtMsgId)) { + if (!item->isImportant()) { + loadImportant = false; + } + } } else if (_delayedShowAtMsgId < 0 && _history->isChannel()) { if (_delayedShowAtMsgId == SwitchAtTopMsgId) { loadImportant = true; @@ -3635,7 +3664,19 @@ void HistoryWidget::onHistoryToEnd() { } void HistoryWidget::onCollapseComments() { - showPeerHistory(_peer->id, SwitchAtTopMsgId); + MsgId switchAt = SwitchAtTopMsgId; + bool collapseCommentsVisible = !_showAnim.animating() && _history && !_firstLoadRequest && _history->isChannel() && !_history->asChannelHistory()->onlyImportant(); + if (collapseCommentsVisible) { + if (HistoryItem *collapse = _history->asChannelHistory()->collapse()) { + if (!collapse->detached()) { + int32 collapseY = (_list->height() - _history->height - st::historyPadding) + collapse->y + collapse->block()->y - _scroll.scrollTop(); + if (collapseY >= 0 && collapseY < _scroll.height()) { + switchAt = collapse->id; + } + } + } + } + showPeerHistory(_peer->id, switchAt); } void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) { @@ -3648,7 +3689,7 @@ void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) { fastShowAtEnd(_history); WebPageId webPageId = _previewCancelled ? 0xFFFFFFFFFFFFFFFFULL : ((_previewData && _previewData->pendingTill >= 0) ? _previewData->id : 0); - App::main()->sendPreparedText(_history, text, replyTo, webPageId); + App::main()->sendPreparedText(_history, text, replyTo, _broadcast.checked(), webPageId); setFieldText(QString()); _saveDraftText = true; @@ -3756,14 +3797,14 @@ void HistoryWidget::shareContact(const PeerId &peer, const QString &phone, const sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id; } - bool fromChannelName = p->isChannel(); + bool fromChannelName = p->isChannel() && p->asChannel()->adminned && _broadcast.checked(); if (fromChannelName) { sendFlags |= MTPmessages_SendMessage_flag_broadcast; flags |= MTPDmessage::flag_views; } else { flags |= MTPDmessage::flag_from_id; } - h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(peer), MTPPeer(), MTPint(), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname), MTP_int(userId)), MTPnullMarkup, MTPnullEntities, MTP_int(1))); + h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(peer), MTPPeer(), MTPint(), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname), MTP_int(userId)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread); h->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), p->input, MTP_int(replyTo), MTP_inputMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, h->sendRequestId); App::historyRegRandom(randomId, newId); @@ -3811,6 +3852,7 @@ void HistoryWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTo _attachPhoto.hide(); _attachEmoji.hide(); _attachMention.hide(); + _broadcast.hide(); _kbShow.hide(); _kbHide.hide(); _cmdStart.hide(); @@ -4072,7 +4114,7 @@ void HistoryWidget::sendBotCommand(const QString &cmd, MsgId replyTo) { // reply toSend += '@' + username; } - App::main()->sendPreparedText(_history, toSend, replyTo ? ((!_peer->isUser()/* && (botStatus == 0 || botStatus == 2)*/) ? replyTo : -1) : 0); + App::main()->sendPreparedText(_history, toSend, false, replyTo ? ((!_peer->isUser()/* && (botStatus == 0 || botStatus == 2)*/) ? replyTo : -1) : 0); if (replyTo) { cancelReply(); if (_keyboard.singleUse() && _keyboard.hasMarkup() && lastKeyboardUsed) { @@ -4189,7 +4231,7 @@ void HistoryWidget::updateDragAreas() { resizeEvent(0); } -bool HistoryWidget::canSendMessages(PeerData *peer) { +bool HistoryWidget::canSendMessages(PeerData *peer) const { if (peer) { if (peer->isUser()) { return peer->asUser()->access != UserNoAccess; @@ -4202,10 +4244,14 @@ bool HistoryWidget::canSendMessages(PeerData *peer) { return false; } -bool HistoryWidget::readyToForward() { +bool HistoryWidget::readyToForward() const { return _canSendMessages && App::main()->hasForwardingItems(); } +bool HistoryWidget::hasBroadcastToggle() const { + return _history && _history->peer->isChannel() && _history->peer->asChannel()->adminned && !_history->peer->asChannel()->isBroadcast; +} + bool HistoryWidget::isBotStart() const { if (!_peer || !_peer->isUser() || !_peer->asUser()->botInfo) return false; return !_peer->asUser()->botInfo->startToken.isEmpty() || (_history->isEmpty() && !_history->lastMsg); @@ -4503,7 +4549,8 @@ void HistoryWidget::onFieldResize() { _botStart.setGeometry(0, _attachDocument.y(), width(), _botStart.height()); _unblock.setGeometry(0, _attachDocument.y(), width(), _unblock.height()); _send.move(width() - _send.width(), _attachDocument.y()); - _attachEmoji.move(_send.x() - _attachEmoji.width(), height() - kbh - _attachEmoji.height()); + _broadcast.move(_send.x() - _broadcast.width(), height() - kbh - _broadcast.height()); + _attachEmoji.move((hasBroadcastToggle() ? _broadcast.x() : _send.x()) - _attachEmoji.width(), height() - kbh - _attachEmoji.height()); _kbShow.move(_attachEmoji.x() - _kbShow.width(), height() - kbh - _kbShow.height()); _kbHide.move(_attachEmoji.x(), _attachEmoji.y()); _cmdStart.move(_attachEmoji.x() - _cmdStart.width(), height() - kbh - _cmdStart.height()); @@ -4674,19 +4721,19 @@ void HistoryWidget::confirmSendImage(const ReadyLocalMedia &img) { int32 flags = newMessageFlags(h->peer) | MTPDmessage::flag_media; // unread, out if (img.replyTo) flags |= MTPDmessage::flag_reply_to_msg_id; - bool fromChannelName = h->peer->isChannel(); + bool fromChannelName = h->peer->isChannel() && h->peer->asChannel()->adminned && _broadcast.checked(); if (fromChannelName) { flags |= MTPDmessage::flag_views; } else { flags |= MTPDmessage::flag_from_id; } if (img.type == ToPreparePhoto) { - h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(img.peer), MTPPeer(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(img.photo, MTP_string("")), MTPnullMarkup, MTPnullEntities, MTP_int(1))); + h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(img.peer), MTPPeer(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(img.photo, MTP_string("")), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread); } else if (img.type == ToPrepareDocument) { - h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(img.peer), MTPPeer(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(img.document), MTPnullMarkup, MTPnullEntities, MTP_int(1))); + h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(img.peer), MTPPeer(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(img.document), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread); } else if (img.type == ToPrepareAudio) { flags |= MTPDmessage_flag_media_unread; - h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(img.peer), MTPPeer(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaAudio(img.audio), MTPnullMarkup, MTPnullEntities, MTP_int(1))); + h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(img.peer), MTPPeer(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaAudio(img.audio), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread); } if (_peer && img.peer == _peer->id) { @@ -4716,7 +4763,7 @@ void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, const MTPInputFile & sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id; } - bool fromChannelName = hist->peer->isChannel(); + bool fromChannelName = hist->peer->isChannel() && hist->peer->asChannel()->adminned && item->fromChannel(); if (fromChannelName) { sendFlags |= MTPmessages_SendMessage_flag_broadcast; } @@ -4761,7 +4808,7 @@ void HistoryWidget::onDocumentUploaded(const FullMsgId &newId, const MTPInputFil sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id; } - bool fromChannelName = hist->peer->isChannel(); + bool fromChannelName = hist->peer->isChannel() && hist->peer->asChannel()->adminned && item->fromChannel(); if (fromChannelName) { sendFlags |= MTPmessages_SendMessage_flag_broadcast; } @@ -4790,7 +4837,7 @@ void HistoryWidget::onThumbDocumentUploaded(const FullMsgId &newId, const MTPInp sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id; } - bool fromChannelName = hist->peer->isChannel(); + bool fromChannelName = hist->peer->isChannel() && hist->peer->asChannel()->adminned && item->fromChannel(); if (fromChannelName) { sendFlags |= MTPmessages_SendMessage_flag_broadcast; } @@ -4817,7 +4864,7 @@ void HistoryWidget::onAudioUploaded(const FullMsgId &newId, const MTPInputFile & sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id; } - bool fromChannelName = hist->peer->isChannel(); + bool fromChannelName = hist->peer->isChannel() && hist->peer->asChannel()->adminned && item->fromChannel(); if (fromChannelName) { sendFlags |= MTPmessages_SendMessage_flag_broadcast; } @@ -4988,7 +5035,7 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) { updateListSize(App::main() ? App::main()->contentScrollAddToY() : 0); bool kbShowShown = _history && !_kbShown && _keyboard.hasMarkup(); - _field.resize(width() - _send.width() - _attachDocument.width() - _attachEmoji.width() - (kbShowShown ? _kbShow.width() : 0) - (_cmdStartShown ? _cmdStart.width() : 0), _field.height()); + _field.resize(width() - _send.width() - _attachDocument.width() - _attachEmoji.width() - (kbShowShown ? _kbShow.width() : 0) - (_cmdStartShown ? _cmdStart.width() : 0) - (hasBroadcastToggle() ? _broadcast.width() : 0), _field.height()); _toHistoryEnd.move((width() - _toHistoryEnd.width()) / 2, _scroll.y() + _scroll.height() - _toHistoryEnd.height() - st::historyToEndSkip); updateCollapseCommentsVisibility(); @@ -4996,7 +5043,8 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) { _send.move(width() - _send.width(), _attachDocument.y()); _botStart.setGeometry(0, _attachDocument.y(), width(), _botStart.height()); _unblock.setGeometry(0, _attachDocument.y(), width(), _unblock.height()); - _attachEmoji.move(_send.x() - _attachEmoji.width(), height() - kbh - _attachEmoji.height()); + _broadcast.move(_send.x() - _broadcast.width(), height() - kbh - _broadcast.height()); + _attachEmoji.move((hasBroadcastToggle() ? _broadcast.x() : _send.x()) - _attachEmoji.width(), height() - kbh - _attachEmoji.height()); _kbShow.move(_attachEmoji.x() - _kbShow.width(), height() - kbh - _kbShow.height()); _kbHide.move(_attachEmoji.x(), _attachEmoji.y()); _cmdStart.move(_attachEmoji.x() - _cmdStart.width(), height() - kbh - _cmdStart.height()); @@ -5295,11 +5343,13 @@ void HistoryWidget::updateCollapseCommentsVisibility() { bool collapseCommentsVisible = !_showAnim.animating() && _history && !_firstLoadRequest && _history->isChannel() && !_history->asChannelHistory()->onlyImportant(); if (collapseCommentsVisible) { if (HistoryItem *collapse = _history->asChannelHistory()->collapse()) { - int32 collapseY = (_list->height() - _history->height - st::historyPadding) + collapse->y + collapse->block()->y - _scroll.scrollTop(); - if (collapseY > _scroll.height()) { - collapseCommentsTop += qMin(collapseY - _scroll.height() - collapse->height(), 0); - } else { - collapseCommentsTop += qMax(collapseY, 0); + if (!collapse->detached()) { + int32 collapseY = (_list->height() - _history->height - st::historyPadding) + collapse->y + collapse->block()->y - _scroll.scrollTop(); + if (collapseY > _scroll.height()) { + collapseCommentsTop += qMin(collapseY - _scroll.height() - collapse->height(), 0); + } else { + collapseCommentsTop += qMax(collapseY, 0); + } } } } @@ -5419,7 +5469,7 @@ void HistoryWidget::onStickerSend(DocumentData *sticker) { flags |= MTPDmessage::flag_reply_to_msg_id; sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id; } - bool fromChannelName = _history->peer->isChannel(); + bool fromChannelName = _history->peer->isChannel() && _history->peer->asChannel()->adminned && _broadcast.checked(); if (fromChannelName) { sendFlags |= MTPmessages_SendMessage_flag_broadcast; } else { @@ -5462,7 +5512,7 @@ void HistoryWidget::setFieldText(const QString &text) { void HistoryWidget::onReplyToMessage() { HistoryItem *to = App::contextItem(); - if (!to || to->id <= 0 || (_peer->isChannel() && !_peer->asChannel()->adminned)) return; + if (!to || to->id <= 0 || !_canSendMessages) return; App::main()->cancelForwarding(); @@ -5723,7 +5773,7 @@ void HistoryWidget::onForwardSelected() { } void HistoryWidget::onDeleteSelected() { - if (!_list || (peer()->isChannel() && !peer()->asChannel()->adminned)) return; + if (!_list) return; SelectedItemSet sel; _list->fillSelectedItems(sel); @@ -5830,8 +5880,8 @@ void HistoryWidget::updateTopBarSelection() { int32 selectedForForward, selectedForDelete; _list->getSelectionState(selectedForForward, selectedForDelete); - _selCount = selectedForDelete ? selectedForDelete : selectedForForward; - App::main()->topBar()->showSelected(_selCount > 0 ? _selCount : 0); + _selCount = selectedForForward ? selectedForForward : selectedForDelete; + App::main()->topBar()->showSelected(_selCount > 0 ? _selCount : 0, (selectedForDelete == selectedForForward)); updateControlsVisibility(); updateListSize(); if (!App::wnd()->layerShown() && !App::passcoded()) { diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 7c302a00b..e57dab693 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -531,6 +531,7 @@ public: void ctrlEnterSubmitUpdated(); void setInnerFocus(); + bool canSendMessages(PeerData *peer) const; ~HistoryWidget(); @@ -690,8 +691,8 @@ private: void updateDragAreas(); - bool canSendMessages(PeerData *peer); - bool readyToForward(); + bool readyToForward() const; + bool hasBroadcastToggle() const; PeerData *_peer, *_clearPeer; // cache _peer in _clearPeer when showing clear history box ChannelId _channel; @@ -725,6 +726,7 @@ private: FlatButton _send, _unblock, _botStart; mtpRequestId _unblockRequest, _reportSpamRequest; IconedButton _attachDocument, _attachPhoto, _attachEmoji, _kbShow, _kbHide, _cmdStart; + FlatCheckbox _broadcast; bool _cmdStartShown; MessageField _field; Animation _recordAnim, _recordingAnim; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index f205353f2..8fde432e2 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -33,7 +33,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org #include "audio.h" TopBarWidget::TopBarWidget(MainWidget *w) : TWidget(w), - a_over(0), _drawShadow(true), _selPeer(0), _selCount(0), _selStrLeft(-st::topBarButton.width / 2), _selStrWidth(0), _animating(false), + a_over(0), _drawShadow(true), _selPeer(0), _selCount(0), _canDelete(false), _selStrLeft(-st::topBarButton.width / 2), _selStrWidth(0), _animating(false), _clearSelection(this, lang(lng_selected_clear), st::topBarButton), _forward(this, lang(lng_selected_forward), st::topBarActionButton), _delete(this, lang(lng_selected_delete), st::topBarActionButton), @@ -321,10 +321,10 @@ void TopBarWidget::showAll() { _deleteContact.hide(); if (!p && _selCount) { _clearSelection.show(); - if ((h && h->isChannel() && !h->asChannel()->adminned) || (o && o->isChannel() && !o->asChannel()->adminned)) { - _delete.hide(); - } else { + if (_canDelete) { _delete.show(); + } else { + _delete.hide(); } _forward.show(); _mediaType.hide(); @@ -347,10 +347,11 @@ void TopBarWidget::showAll() { resizeEvent(0); } -void TopBarWidget::showSelected(uint32 selCount) { +void TopBarWidget::showSelected(uint32 selCount, bool canDelete) { PeerData *p = App::main() ? App::main()->profilePeer() : 0; _selPeer = App::main()->overviewPeer() ? App::main()->overviewPeer() : App::main()->peer(); _selCount = selCount; + _canDelete = canDelete; _selStr = (_selCount > 0) ? lng_selected_count(lt_count, _selCount) : QString(); _selStrWidth = st::btnDefLink.font->m.width(_selStr); setCursor((!p && _selCount) ? style::cur_default : style::cur_pointer); @@ -930,6 +931,7 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu LOG(("API Error: received messages.channelMessages when no channel was passed! (MainWidget::checkedHistory)")); } + // CHANNELS_TODO use collapsed to remove last important messages from not important after History::addNewMessage App::feedUsers(d.vusers); App::feedChats(d.vchats); v = &d.vmessages.c_vector().v; @@ -943,14 +945,14 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu if (history.peer() == peer) { showDialogs(); } - } else { + } else { // CHANNELS_TODO History *h = App::historyLoaded(peer->id); if (h) Local::addSavedPeer(peer, h->lastMsgDate); } } else { History *h = App::historyLoaded(peer->id); if (!h->lastMsg) { - h->addNewMessage((*v)[0], 0); + h->addNewMessage((*v)[0], NewMessageLast); } } } @@ -1135,7 +1137,7 @@ QString cleanMessage(const QString &text) { return result; } -void MainWidget::sendPreparedText(History *hist, const QString &text, MsgId replyTo, WebPageId webPageId) { +void MainWidget::sendPreparedText(History *hist, const QString &text, MsgId replyTo, bool broadcast, WebPageId webPageId) { saveRecentHashtags(text); QString sendingText, leftText = text; if (replyTo < 0) replyTo = history.replyToId(); @@ -1163,7 +1165,7 @@ void MainWidget::sendPreparedText(History *hist, const QString &text, MsgId repl media = MTP_messageMediaWebPage(MTP_webPagePending(MTP_long(page->id), MTP_int(page->pendingTill))); flags |= MTPDmessage::flag_media; } - bool fromChannelName = hist->peer->isChannel(); + bool fromChannelName = hist->peer->isChannel() && hist->peer->asChannel()->adminned && broadcast; if (fromChannelName) { sendFlags |= MTPmessages_SendMessage_flag_broadcast; flags |= MTPDmessage::flag_views; @@ -1171,19 +1173,19 @@ void MainWidget::sendPreparedText(History *hist, const QString &text, MsgId repl flags |= MTPDmessage::flag_from_id; } MTPVector localEntities = linksToMTP(textParseLinks(sendingText, itemTextParseOptions(hist, App::self()).flags)); - hist->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(hist->peer->id), MTPPeer(), MTPint(), MTP_int(replyTo), MTP_int(unixtime()), msgText, media, MTPnullMarkup, localEntities, MTP_int(1))); + hist->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(hist->peer->id), MTPPeer(), MTPint(), MTP_int(replyTo), MTP_int(unixtime()), msgText, media, MTPnullMarkup, localEntities, MTP_int(1)), NewMessageUnread); hist->sendRequestId = MTP::send(MTPmessages_SendMessage(MTP_int(sendFlags), hist->peer->input, MTP_int(replyTo), msgText, MTP_long(randomId), MTPnullMarkup, localEntities), rpcDone(&MainWidget::sentUpdatesReceived, randomId), rpcFail(&MainWidget::sendMessageFail), 0, 0, hist->sendRequestId); } finishForwarding(hist); } -void MainWidget::sendMessage(History *hist, const QString &text, MsgId replyTo) { +void MainWidget::sendMessage(History *hist, const QString &text, MsgId replyTo, bool broadcast) { MsgId fixInScrollMsgId = 0; int32 fixInScrollMsgTop = 0; hist->getReadyFor(ShowAtTheEndMsgId, fixInScrollMsgId, fixInScrollMsgTop); readServerHistory(hist, false); - sendPreparedText(hist, history.prepareMessage(text), replyTo); + sendPreparedText(hist, history.prepareMessage(text), replyTo, broadcast); } void MainWidget::saveRecentHashtags(const QString &text) { @@ -1553,7 +1555,7 @@ void MainWidget::overviewLoaded(History *h, const MTPmessages_Messages &msgs, mt } for (QVector::const_iterator i = v->cbegin(), e = v->cend(); i != e; ++i) { - HistoryItem *item = App::histories().addNewMessage(*i, -1); + HistoryItem *item = App::histories().addNewMessage(*i, NewMessageExisting); if (item && h->overviewIds[type].constFind(item->id) == h->overviewIds[type].cend()) { h->overviewIds[type].insert(item->id, NullType()); h->overview[type].push_front(item->id); @@ -1981,13 +1983,13 @@ void MainWidget::dialogsCancelled() { history.activate(); } -void MainWidget::serviceNotification(const QString &msg, const MTPMessageMedia &media, bool unread) { - int32 flags = (unread ? MTPDmessage_flag_unread : 0) | MTPDmessage::flag_entities | MTPDmessage::flag_from_id; +void MainWidget::serviceNotification(const QString &msg, const MTPMessageMedia &media) { + int32 flags = MTPDmessage_flag_unread | MTPDmessage::flag_entities | MTPDmessage::flag_from_id; QString sendingText, leftText = msg; HistoryItem *item = 0; while (textSplit(sendingText, leftText, MaxMessageSize)) { MTPVector localEntities = linksToMTP(textParseLinks(sendingText, _historyTextOptions.flags)); - item = App::histories().addNewMessage(MTP_message(MTP_int(flags), MTP_int(clientMsgId()), MTP_int(ServiceUserId), MTP_peerUser(MTP_int(MTP::authedId())), MTPPeer(), MTPint(), MTPint(), MTP_int(unixtime()), MTP_string(sendingText), media, MTPnullMarkup, localEntities, MTPint()), unread ? 1 : 2); + item = App::histories().addNewMessage(MTP_message(MTP_int(flags), MTP_int(clientMsgId()), MTP_int(ServiceUserId), MTP_peerUser(MTP_int(MTP::authedId())), MTPPeer(), MTPint(), MTPint(), MTP_int(unixtime()), MTP_string(sendingText), media, MTPnullMarkup, localEntities, MTPint()), NewMessageUnread); } if (item) { history.peerMessagesUpdated(item->history()->peer->id); @@ -2000,14 +2002,14 @@ void MainWidget::serviceHistoryDone(const MTPmessages_Messages &msgs) { const MTPDmessages_messages &d(msgs.c_messages_messages()); App::feedUsers(d.vusers); App::feedChats(d.vchats); - App::feedMsgs(d.vmessages); + App::feedMsgs(d.vmessages, NewMessageLast); } break; case mtpc_messages_messagesSlice: { const MTPDmessages_messagesSlice &d(msgs.c_messages_messagesSlice()); App::feedUsers(d.vusers); App::feedChats(d.vchats); - App::feedMsgs(d.vmessages); + App::feedMsgs(d.vmessages, NewMessageLast); } break; case mtpc_messages_channelMessages: { @@ -2019,7 +2021,7 @@ void MainWidget::serviceHistoryDone(const MTPmessages_Messages &msgs) { App::feedUsers(d.vusers); App::feedChats(d.vchats); - App::feedMsgs(d.vmessages); + App::feedMsgs(d.vmessages, NewMessageLast); } break; } @@ -2193,6 +2195,8 @@ void MainWidget::showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool back) back = true; } + PeerData *wasActivePeer = activePeer(); + App::wnd()->hideLayer(); if (_hider) { _hider->startHide(); @@ -2258,6 +2262,9 @@ void MainWidget::showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool back) if (noPeer) { _topBar.hide(); resizeEvent(0); + } else if (wasActivePeer != activePeer() && activePeer()->isChannel()) { + activePeer()->asChannel()->ptsWaitingForShortPoll(true); + ptsWaiterStartTimerFor(history.peer()->asChannel(), WaitForChannelGetDifference); } if (!cWideMode() && !dialogs.isHidden()) dialogs.hide(); if (!animating()) { @@ -2269,6 +2276,9 @@ void MainWidget::showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool back) } } } + //if (wasActivePeer && wasActivePeer->isChannel() && activePeer() != wasActivePeer) { + // wasActivePeer->asChannel()->ptsStopShortPoll(); + //} if (!dialogs.isHidden()) { dialogs.scrollToPeer(peerId, showAtMsgId); @@ -2874,8 +2884,13 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha App::feedUsers(d.vusers); App::feedChats(d.vchats); - App::feedMsgs(d.vmessages); - if (History *h = App::historyLoaded(channel->id)) { + History *h = App::historyLoaded(channel->id); + if (h) { + h->setNotLoadedAtBottom(); + h->asChannelHistory()->clearOther(); + } + App::feedMsgs(d.vmessages, NewMessageLast); + if (h) { if (HistoryItem *item = App::histItemById(peerToChannel(channel->id), d.vtop_important_message.v)) { h->setLastMessage(item); } @@ -2883,14 +2898,14 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha h->setUnreadCount(d.vunread_important_count.v, false); h->inboxReadBefore = d.vread_inbox_max_id.v + 1; } - h->setNotLoadedAtBottom(); + if (d.vunread_count.v >= h->asChannelHistory()->unreadCountAll) { + h->asChannelHistory()->unreadCountAll = d.vunread_count.v; + h->inboxReadBefore = d.vread_inbox_max_id.v + 1; + } if (history.peer() == channel) { history.updateToEndVisibility(); - if (d.vunread_count.v >= h->asChannelHistory()->unreadCountAll) { - h->asChannelHistory()->unreadCountAll = d.vunread_count.v; - h->inboxReadBefore = d.vread_inbox_max_id.v + 1; - } } +// h->asChannelHistory()->getRangeDifference(); } if (d.has_timeout()) timeout = d.vtimeout.v; @@ -2904,7 +2919,7 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha App::feedUsers(d.vusers); App::feedChats(d.vchats, false); feedMessageIds(d.vother_updates); - App::feedMsgs(d.vnew_messages, 1); + App::feedMsgs(d.vnew_messages, NewMessageUnread); feedUpdates(d.vother_updates, true); if (d.has_timeout()) timeout = d.vtimeout.v; @@ -2918,8 +2933,9 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha if (!(flags & MTPupdates_ChannelDifference_flag_final)) { MTP_LOG(0, ("getChannelDifference { good - after not final channelDifference was received }%1").arg(cTestMode() ? " TESTMODE" : "")); getChannelDifference(channel); - } else if (timeout) { -// QTimer::singleShot(timeout * 1000, this, SLOT(getDifference())); + } else if (activePeer() == channel) { + channel->ptsWaitingForShortPoll(true); + ptsWaiterStartTimerFor(channel, timeout ? (timeout * 1000) : WaitForChannelGetDifference); } App::emitPeerUpdated(); @@ -3073,7 +3089,7 @@ void MainWidget::feedDifference(const MTPVector &users, const MTPVector App::feedUsers(users, false); App::feedChats(chats, false); feedMessageIds(other); - App::feedMsgs(msgs, 1); + App::feedMsgs(msgs, NewMessageUnread); feedUpdates(other, true); history.peerMessagesUpdated(); } @@ -3182,7 +3198,23 @@ void MainWidget::getChannelDifference(ChannelData *channel, GetChannelDifference LOG(("Getting channel difference for %1").arg(channel->pts())); channel->ptsSetRequesting(true); - MTP::send(MTPupdates_GetChannelDifference(channel->inputChannel, MTP_channelMessagesFilterCollapsed(), MTP_int(channel->pts()), MTP_int(MTPChannelGetDifferenceLimit)), rpcDone(&MainWidget::gotChannelDifference, channel), rpcFail(&MainWidget::failChannelDifference, channel)); + MTPChannelMessagesFilter filter; + if (activePeer() == channel) { + filter = MTP_channelMessagesFilterEmpty(); + } else { + filter = MTP_channelMessagesFilterCollapsed(); + if (History *history = App::historyLoaded(channel->id)) { + if (!history->asChannelHistory()->onlyImportant()) { + MsgId fixInScrollMsgId = 0; + int32 fixInScrollMsgTop = 0; + history->asChannelHistory()->getSwitchReadyFor(SwitchAtTopMsgId, fixInScrollMsgId, fixInScrollMsgTop); + history->getReadyFor(ShowAtTheEndMsgId, fixInScrollMsgId, fixInScrollMsgTop); + history->lastWidth = 0; + history->lastScrollTop = INT_MAX; + } + } + } + MTP::send(MTPupdates_GetChannelDifference(channel->inputChannel, filter, MTP_int(channel->pts()), MTP_int(3/*MTPChannelGetDifferenceLimit*/)), rpcDone(&MainWidget::gotChannelDifference, channel), rpcFail(&MainWidget::failChannelDifference, channel)); } void MainWidget::mtpPing() { @@ -3792,7 +3824,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates, uint64 randomId) { } int32 flags = d.vflags.v | MTPDmessage::flag_from_id; bool out = (flags & MTPDmessage_flag_out); - HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_int(flags), d.vid, out ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(out ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint())); + HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_int(flags), d.vid, out ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(out ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint()), NewMessageUnread); if (item) { history.peerMessagesUpdated(item->history()->peer->id); } @@ -3813,7 +3845,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates, uint64 randomId) { } int32 flags = d.vflags.v | MTPDmessage::flag_from_id; bool out = (flags & MTPDmessage_flag_out); - HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_int(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint())); + HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_int(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from_id, d.vfwd_date, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint()), NewMessageUnread); if (item) { history.peerMessagesUpdated(item->history()->peer->id); } @@ -3876,7 +3908,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { App::checkEntitiesAndViewsUpdate(d.vmessage.c_message()); } - HistoryItem *item = App::histories().addNewMessage(d.vmessage); + HistoryItem *item = App::histories().addNewMessage(d.vmessage, NewMessageUnread); if (item) { history.peerMessagesUpdated(item->history()->peer->id); } @@ -4159,9 +4191,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { const MTPDupdateServiceNotification &d(update.c_updateServiceNotification()); if (d.vpopup.v) { App::wnd()->showLayer(new ConfirmBox(qs(d.vmessage), true)); - App::wnd()->serviceNotification(qs(d.vmessage), false, d.vmedia); + App::wnd()->serviceNotification(qs(d.vmessage), d.vmedia); } else { - App::wnd()->serviceNotification(qs(d.vmessage), true, d.vmedia); + App::wnd()->serviceNotification(qs(d.vmessage), d.vmedia); } } break; @@ -4169,6 +4201,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { const MTPDupdatePrivacy &d(update.c_updatePrivacy()); } break; + case mtpc_updateChannel: { + const MTPDupdateChannel &d(update.c_updateChannel()); + App::markPeerUpdated(App::channelLoaded(d.vchannel_id.v)); + } break; + case mtpc_updateNewChannelMessage: { const MTPDupdateNewChannelMessage &d(update.c_updateNewChannelMessage()); PeerId peer = peerFromMessage(d.vmessage); @@ -4181,7 +4218,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { App::checkEntitiesAndViewsUpdate(d.vmessage.c_message()); } - HistoryItem *item = App::histories().addNewMessage(d.vmessage); + HistoryItem *item = App::histories().addNewMessage(d.vmessage, NewMessageUnread); if (item) { history.peerMessagesUpdated(item->history()->peer->id); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 72e7a31f2..4ee446def 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -50,7 +50,7 @@ public: void startAnim(); void stopAnim(); void showAll(); - void showSelected(uint32 selCount); + void showSelected(uint32 selCount, bool canDelete = false); FlatButton *mediaTypeButton(); @@ -79,6 +79,7 @@ private: PeerData *_selPeer; uint32 _selCount; + bool _canDelete; QString _selStr; int32 _selStrLeft, _selStrWidth; @@ -311,8 +312,8 @@ public: DialogsIndexed &contactsList(); DialogsIndexed &dialogsList(); - void sendMessage(History *history, const QString &text, MsgId replyTo); - void sendPreparedText(History *hist, const QString &text, MsgId replyTo, WebPageId webPageId = 0); + void sendMessage(History *history, const QString &text, MsgId replyTo, bool broadcast); + void sendPreparedText(History *hist, const QString &text, MsgId replyTo, bool broadcast, WebPageId webPageId = 0); void saveRecentHashtags(const QString &text); void readServerHistory(History *history, bool force = true); @@ -338,7 +339,7 @@ public: void showAddContact(); void showNewGroup(); - void serviceNotification(const QString &msg, const MTPMessageMedia &media, bool unread); + void serviceNotification(const QString &msg, const MTPMessageMedia &media); void serviceHistoryDone(const MTPmessages_Messages &msgs); bool serviceHistoryFail(const RPCError &error); diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.cpp b/Telegram/SourceFiles/mtproto/mtpScheme.cpp index 1e0d64be7..7acd65367 100644 --- a/Telegram/SourceFiles/mtproto/mtpScheme.cpp +++ b/Telegram/SourceFiles/mtproto/mtpScheme.cpp @@ -1302,15 +1302,18 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP to.add("\n").addSpaces(lev); } switch (stage) { - case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 1: to.add(" participants: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 2: to.add(" about: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 3: to.add(" read_inbox_max_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 4: to.add(" unread_count: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 5: to.add(" unread_important_count: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 6: to.add(" chat_photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 7: to.add(" notify_settings: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 8: to.add(" exported_invite: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 3: to.add(" participants_count: "); ++stages.back(); if (flag & MTPDchannelFull::flag_participants_count) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; + case 4: to.add(" admins_count: "); ++stages.back(); if (flag & MTPDchannelFull::flag_admins_count) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; + case 5: to.add(" kicked_count: "); ++stages.back(); if (flag & MTPDchannelFull::flag_kicked_count) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break; + case 6: to.add(" read_inbox_max_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 7: to.add(" unread_count: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 8: to.add(" unread_important_count: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 9: to.add(" chat_photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 10: to.add(" notify_settings: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 11: to.add(" exported_invite: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } break; @@ -4576,23 +4579,6 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP } break; - case mtpc_channelParticipants: - if (stage) { - to.add(",\n").addSpaces(lev); - } else { - to.add("{ channelParticipants"); - to.add("\n").addSpaces(lev); - } - switch (stage) { - case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 1: to.add(" channel_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 2: to.add(" participants_count: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 3: to.add(" self_participant: "); ++stages.back(); if (flag & MTPDchannelParticipants::flag_self_participant) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; - case 4: to.add(" participants: "); ++stages.back(); if (flag & MTPDchannelParticipants::flag_participants) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; - default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; - } - break; - case mtpc_messageRange: if (stage) { to.add(",\n").addSpaces(lev); diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.h b/Telegram/SourceFiles/mtproto/mtpScheme.h index 520287354..947a09276 100644 --- a/Telegram/SourceFiles/mtproto/mtpScheme.h +++ b/Telegram/SourceFiles/mtproto/mtpScheme.h @@ -138,7 +138,7 @@ enum { mtpc_channel = 0x678e9587, mtpc_channelForbidden = 0x2d85832c, mtpc_chatFull = 0x2e02a614, - mtpc_channelFull = 0x36949a50, + mtpc_channelFull = 0xfab31aa3, mtpc_chatParticipant = 0xc8d7493e, mtpc_chatParticipantsForbidden = 0xfc900c2b, mtpc_chatParticipants = 0x7841b415, @@ -401,7 +401,6 @@ enum { mtpc_inputChannelEmpty = 0xee8c1e86, mtpc_inputChannel = 0xafeb712e, mtpc_contacts_resolvedPeer = 0x7f077ad9, - mtpc_channelParticipants = 0xdee6d213, mtpc_messageRange = 0xae30253, mtpc_messageGroup = 0xe8346f53, mtpc_updates_channelDifferenceEmpty = 0x3e11affb, @@ -1136,9 +1135,6 @@ class MTPDinputChannel; class MTPcontacts_resolvedPeer; class MTPDcontacts_resolvedPeer; -class MTPchannelParticipants; -class MTPDchannelParticipants; - class MTPmessageRange; class MTPDmessageRange; @@ -1317,7 +1313,6 @@ typedef MTPBoxed MTPhelp_AppChangelog; typedef MTPBoxed MTPMessageEntity; typedef MTPBoxed MTPInputChannel; typedef MTPBoxed MTPcontacts_ResolvedPeer; -typedef MTPBoxed MTPChannelParticipants; typedef MTPBoxed MTPMessageRange; typedef MTPBoxed MTPMessageGroup; typedef MTPBoxed MTPupdates_ChannelDifference; @@ -3308,7 +3303,7 @@ private: explicit MTPchatFull(MTPDchannelFull *_data); friend MTPchatFull MTP_chatFull(MTPint _id, const MTPChatParticipants &_participants, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite, const MTPVector &_bot_info); - friend MTPchatFull MTP_channelFull(MTPint _id, const MTPChannelParticipants &_participants, const MTPstring &_about, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite); + friend MTPchatFull MTP_channelFull(MTPint _flags, MTPint _id, const MTPstring &_about, MTPint _participants_count, MTPint _admins_count, MTPint _kicked_count, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite); mtpTypeId _type; }; @@ -8236,37 +8231,6 @@ private: }; typedef MTPBoxed MTPcontacts_ResolvedPeer; -class MTPchannelParticipants : private mtpDataOwner { -public: - MTPchannelParticipants(); - MTPchannelParticipants(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channelParticipants) : mtpDataOwner(0) { - read(from, end, cons); - } - - MTPDchannelParticipants &_channelParticipants() { - if (!data) throw mtpErrorUninitialized(); - split(); - return *(MTPDchannelParticipants*)data; - } - const MTPDchannelParticipants &c_channelParticipants() const { - if (!data) throw mtpErrorUninitialized(); - return *(const MTPDchannelParticipants*)data; - } - - uint32 innerLength() const; - mtpTypeId type() const; - void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channelParticipants); - void write(mtpBuffer &to) const; - - typedef void ResponseType; - -private: - explicit MTPchannelParticipants(MTPDchannelParticipants *_data); - - friend MTPchannelParticipants MTP_channelParticipants(MTPint _flags, MTPint _channel_id, MTPint _participants_count, const MTPChannelParticipant &_self_participant, const MTPVector &_participants); -}; -typedef MTPBoxed MTPChannelParticipants; - class MTPmessageRange : private mtpDataOwner { public: MTPmessageRange(); @@ -9588,18 +9552,31 @@ class MTPDchannelFull : public mtpDataImpl { public: MTPDchannelFull() { } - MTPDchannelFull(MTPint _id, const MTPChannelParticipants &_participants, const MTPstring &_about, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite) : vid(_id), vparticipants(_participants), vabout(_about), vread_inbox_max_id(_read_inbox_max_id), vunread_count(_unread_count), vunread_important_count(_unread_important_count), vchat_photo(_chat_photo), vnotify_settings(_notify_settings), vexported_invite(_exported_invite) { + MTPDchannelFull(MTPint _flags, MTPint _id, const MTPstring &_about, MTPint _participants_count, MTPint _admins_count, MTPint _kicked_count, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite) : vflags(_flags), vid(_id), vabout(_about), vparticipants_count(_participants_count), vadmins_count(_admins_count), vkicked_count(_kicked_count), vread_inbox_max_id(_read_inbox_max_id), vunread_count(_unread_count), vunread_important_count(_unread_important_count), vchat_photo(_chat_photo), vnotify_settings(_notify_settings), vexported_invite(_exported_invite) { } + MTPint vflags; MTPint vid; - MTPChannelParticipants vparticipants; MTPstring vabout; + MTPint vparticipants_count; + MTPint vadmins_count; + MTPint vkicked_count; MTPint vread_inbox_max_id; MTPint vunread_count; MTPint vunread_important_count; MTPPhoto vchat_photo; MTPPeerNotifySettings vnotify_settings; MTPExportedChatInvite vexported_invite; + + enum { + flag_participants_count = (1 << 0), + flag_admins_count = (1 << 1), + flag_kicked_count = (1 << 2), + }; + + bool has_participants_count() const { return vflags.v & flag_participants_count; } + bool has_admins_count() const { return vflags.v & flag_admins_count; } + bool has_kicked_count() const { return vflags.v & flag_kicked_count; } }; class MTPDchatParticipant : public mtpDataImpl { @@ -12126,28 +12103,6 @@ public: MTPVector vusers; }; -class MTPDchannelParticipants : public mtpDataImpl { -public: - MTPDchannelParticipants() { - } - MTPDchannelParticipants(MTPint _flags, MTPint _channel_id, MTPint _participants_count, const MTPChannelParticipant &_self_participant, const MTPVector &_participants) : vflags(_flags), vchannel_id(_channel_id), vparticipants_count(_participants_count), vself_participant(_self_participant), vparticipants(_participants) { - } - - MTPint vflags; - MTPint vchannel_id; - MTPint vparticipants_count; - MTPChannelParticipant vself_participant; - MTPVector vparticipants; - - enum { - flag_self_participant = (1 << 0), - flag_participants = (1 << 1), - }; - - bool has_self_participant() const { return vflags.v & flag_self_participant; } - bool has_participants() const { return vflags.v & flag_participants; } -}; - class MTPDmessageRange : public mtpDataImpl { public: MTPDmessageRange() { @@ -21270,7 +21225,7 @@ inline uint32 MTPchatFull::innerLength() const { } case mtpc_channelFull: { const MTPDchannelFull &v(c_channelFull()); - return v.vid.innerLength() + v.vparticipants.innerLength() + v.vabout.innerLength() + v.vread_inbox_max_id.innerLength() + v.vunread_count.innerLength() + v.vunread_important_count.innerLength() + v.vchat_photo.innerLength() + v.vnotify_settings.innerLength() + v.vexported_invite.innerLength(); + return v.vflags.innerLength() + v.vid.innerLength() + v.vabout.innerLength() + (v.has_participants_count() ? v.vparticipants_count.innerLength() : 0) + (v.has_admins_count() ? v.vadmins_count.innerLength() : 0) + (v.has_kicked_count() ? v.vkicked_count.innerLength() : 0) + v.vread_inbox_max_id.innerLength() + v.vunread_count.innerLength() + v.vunread_important_count.innerLength() + v.vchat_photo.innerLength() + v.vnotify_settings.innerLength() + v.vexported_invite.innerLength(); } } return 0; @@ -21295,9 +21250,12 @@ inline void MTPchatFull::read(const mtpPrime *&from, const mtpPrime *end, mtpTyp case mtpc_channelFull: _type = cons; { if (!data) setData(new MTPDchannelFull()); MTPDchannelFull &v(_channelFull()); + v.vflags.read(from, end); v.vid.read(from, end); - v.vparticipants.read(from, end); v.vabout.read(from, end); + if (v.has_participants_count()) { v.vparticipants_count.read(from, end); } else { v.vparticipants_count = MTPint(); } + if (v.has_admins_count()) { v.vadmins_count.read(from, end); } else { v.vadmins_count = MTPint(); } + if (v.has_kicked_count()) { v.vkicked_count.read(from, end); } else { v.vkicked_count = MTPint(); } v.vread_inbox_max_id.read(from, end); v.vunread_count.read(from, end); v.vunread_important_count.read(from, end); @@ -21321,9 +21279,12 @@ inline void MTPchatFull::write(mtpBuffer &to) const { } break; case mtpc_channelFull: { const MTPDchannelFull &v(c_channelFull()); + v.vflags.write(to); v.vid.write(to); - v.vparticipants.write(to); v.vabout.write(to); + if (v.has_participants_count()) v.vparticipants_count.write(to); + if (v.has_admins_count()) v.vadmins_count.write(to); + if (v.has_kicked_count()) v.vkicked_count.write(to); v.vread_inbox_max_id.write(to); v.vunread_count.write(to); v.vunread_important_count.write(to); @@ -21347,8 +21308,8 @@ inline MTPchatFull::MTPchatFull(MTPDchannelFull *_data) : mtpDataOwner(_data), _ inline MTPchatFull MTP_chatFull(MTPint _id, const MTPChatParticipants &_participants, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite, const MTPVector &_bot_info) { return MTPchatFull(new MTPDchatFull(_id, _participants, _chat_photo, _notify_settings, _exported_invite, _bot_info)); } -inline MTPchatFull MTP_channelFull(MTPint _id, const MTPChannelParticipants &_participants, const MTPstring &_about, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite) { - return MTPchatFull(new MTPDchannelFull(_id, _participants, _about, _read_inbox_max_id, _unread_count, _unread_important_count, _chat_photo, _notify_settings, _exported_invite)); +inline MTPchatFull MTP_channelFull(MTPint _flags, MTPint _id, const MTPstring &_about, MTPint _participants_count, MTPint _admins_count, MTPint _kicked_count, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite) { + return MTPchatFull(new MTPDchannelFull(_flags, _id, _about, _participants_count, _admins_count, _kicked_count, _read_inbox_max_id, _unread_count, _unread_important_count, _chat_photo, _notify_settings, _exported_invite)); } inline MTPchatParticipant::MTPchatParticipant() : mtpDataOwner(new MTPDchatParticipant()) { @@ -27999,41 +27960,6 @@ inline MTPcontacts_resolvedPeer MTP_contacts_resolvedPeer(const MTPPeer &_peer, return MTPcontacts_resolvedPeer(new MTPDcontacts_resolvedPeer(_peer, _chats, _users)); } -inline MTPchannelParticipants::MTPchannelParticipants() : mtpDataOwner(new MTPDchannelParticipants()) { -} - -inline uint32 MTPchannelParticipants::innerLength() const { - const MTPDchannelParticipants &v(c_channelParticipants()); - return v.vflags.innerLength() + v.vchannel_id.innerLength() + v.vparticipants_count.innerLength() + (v.has_self_participant() ? v.vself_participant.innerLength() : 0) + (v.has_participants() ? v.vparticipants.innerLength() : 0); -} -inline mtpTypeId MTPchannelParticipants::type() const { - return mtpc_channelParticipants; -} -inline void MTPchannelParticipants::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { - if (cons != mtpc_channelParticipants) throw mtpErrorUnexpected(cons, "MTPchannelParticipants"); - - if (!data) setData(new MTPDchannelParticipants()); - MTPDchannelParticipants &v(_channelParticipants()); - v.vflags.read(from, end); - v.vchannel_id.read(from, end); - v.vparticipants_count.read(from, end); - if (v.has_self_participant()) { v.vself_participant.read(from, end); } else { v.vself_participant = MTPChannelParticipant(); } - if (v.has_participants()) { v.vparticipants.read(from, end); } else { v.vparticipants = MTPVector(); } -} -inline void MTPchannelParticipants::write(mtpBuffer &to) const { - const MTPDchannelParticipants &v(c_channelParticipants()); - v.vflags.write(to); - v.vchannel_id.write(to); - v.vparticipants_count.write(to); - if (v.has_self_participant()) v.vself_participant.write(to); - if (v.has_participants()) v.vparticipants.write(to); -} -inline MTPchannelParticipants::MTPchannelParticipants(MTPDchannelParticipants *_data) : mtpDataOwner(_data) { -} -inline MTPchannelParticipants MTP_channelParticipants(MTPint _flags, MTPint _channel_id, MTPint _participants_count, const MTPChannelParticipant &_self_participant, const MTPVector &_participants) { - return MTPchannelParticipants(new MTPDchannelParticipants(_flags, _channel_id, _participants_count, _self_participant, _participants)); -} - inline MTPmessageRange::MTPmessageRange() : mtpDataOwner(new MTPDmessageRange()) { } diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index 12f2095b7..d5c19b9ac 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -222,7 +222,7 @@ channel#678e9587 flags:# id:int access_hash:long title:string username:flags.6?s channelForbidden#2d85832c id:int access_hash:long title:string = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; -channelFull#36949a50 id:int participants:ChannelParticipants about:string read_inbox_max_id:int unread_count:int unread_important_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite = ChatFull; +channelFull#fab31aa3 flags:# id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int unread_count:int unread_important_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; @@ -587,8 +587,6 @@ inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; -channelParticipants#dee6d213 flags:# channel_id:int participants_count:int self_participant:flags.0?ChannelParticipant participants:flags.1?Vector = ChannelParticipants; - messageRange#ae30253 min_id:int max_id:int = MessageRange; messageGroup#e8346f53 min_id:int max_id:int count:int date:int = MessageGroup; diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 8c46ef23f..0c5ccc968 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -350,7 +350,7 @@ void OverviewInner::searchReceived(bool fromStart, const MTPmessages_Messages &r _itemsToBeLoaded = LinksOverviewPerPage * 2; } for (QVector::const_iterator i = messages->cbegin(), e = messages->cend(); i != e; ++i) { - HistoryItem *item = App::histories().addNewMessage(*i, -1); + HistoryItem *item = App::histories().addNewMessage(*i, NewMessageExisting); _searchResults.push_front(item->id); _lastSearchId = item->id; } @@ -1745,6 +1745,9 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } } + int32 selectedForForward, selectedForDelete; + getSelectionState(selectedForForward, selectedForDelete); + // -2 - has full selected items, but not over, 0 - no selection, 2 - over full selected items int32 isUponSelected = 0, hasSelected = 0; if (!_selected.isEmpty()) { @@ -1787,7 +1790,7 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } if (isUponSelected > 1) { _menu->addAction(lang(lng_context_forward_selected), _overview, SLOT(onForwardSelected())); - if (!_peer->isChannel() || _peer->asChannel()->adminned) { + if (selectedForDelete == selectedForForward) { _menu->addAction(lang(lng_context_delete_selected), _overview, SLOT(onDeleteSelected())); } _menu->addAction(lang(lng_context_clear_selection), _overview, SLOT(onClearSelected())); @@ -1796,11 +1799,11 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (App::hoveredLinkItem()->toHistoryMessage()) { _menu->addAction(lang(lng_context_forward_msg), this, SLOT(forwardMessage()))->setEnabled(true); } - if (!_peer->isChannel() || _peer->asChannel()->adminned) { + if (!_peer->isChannel() || _peer->asChannel()->adminned || App::hoveredLinkItem()->out()) { _menu->addAction(lang(lng_context_delete_msg), this, SLOT(deleteMessage()))->setEnabled(true); } } - if (App::hoveredLinkItem()->id > 0 && (!_peer->isChannel() || _peer->asChannel()->adminned)) { + if (App::hoveredLinkItem()->id > 0) { _menu->addAction(lang(lng_context_select_msg), this, SLOT(selectMessage()))->setEnabled(true); } } @@ -1827,7 +1830,7 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { _menu->addAction(lang(lng_context_to_msg), this, SLOT(goToMessage()))->setEnabled(true); if (isUponSelected > 1) { _menu->addAction(lang(lng_context_forward_selected), _overview, SLOT(onForwardSelected())); - if (!_peer->isChannel() || _peer->asChannel()->adminned) { + if (selectedForDelete == selectedForForward) { _menu->addAction(lang(lng_context_delete_selected), _overview, SLOT(onDeleteSelected())); } _menu->addAction(lang(lng_context_clear_selection), _overview, SLOT(onClearSelected())); @@ -1836,11 +1839,11 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (App::mousedItem()->toHistoryMessage()) { _menu->addAction(lang(lng_context_forward_msg), this, SLOT(forwardMessage()))->setEnabled(true); } - if (!_peer->isChannel() || _peer->asChannel()->adminned) { + if (!_peer->isChannel() || _peer->asChannel()->adminned || App::mousedItem()->out()) { _menu->addAction(lang(lng_context_delete_msg), this, SLOT(deleteMessage()))->setEnabled(true); } } - if (App::mousedItem()->id > 0 && (!_peer->isChannel() || _peer->asChannel()->adminned)) { + if (App::mousedItem()->id > 0) { _menu->addAction(lang(lng_context_select_msg), this, SLOT(selectMessage()))->setEnabled(true); } } @@ -2097,10 +2100,14 @@ void OverviewInner::getSelectionState(int32 &selectedForForward, int32 &selected selectedForForward = selectedForDelete = 0; for (SelectedItems::const_iterator i = _selected.cbegin(), e = _selected.cend(); i != e; ++i) { if (i.value() == FullItemSel) { - ++selectedForDelete; - if (i.key() > 0) { - ++selectedForForward; + if (!_peer || !_peer->isChannel() || _peer->asChannel()->adminned) { + ++selectedForDelete; + } else if (HistoryItem *item = App::histItemById(_channel, i.key())) { + if (item->out()) { + ++selectedForDelete; + } } + ++selectedForForward; } } if (!selectedForDelete && !selectedForForward && !_selected.isEmpty()) { // text selection @@ -2719,10 +2726,10 @@ void OverviewWidget::switchType(MediaOverviewType type) { void OverviewWidget::updateTopBarSelection() { int32 selectedForForward, selectedForDelete; _inner.getSelectionState(selectedForForward, selectedForDelete); - _selCount = selectedForDelete ? selectedForDelete : selectedForForward; + _selCount = selectedForForward ? selectedForForward : selectedForDelete; _inner.setSelectMode(_selCount > 0); if (App::main()) { - App::main()->topBar()->showSelected(_selCount > 0 ? _selCount : 0); + App::main()->topBar()->showSelected(_selCount > 0 ? _selCount : 0, (selectedForDelete == selectedForForward)); App::main()->topBar()->update(); } if (App::wnd() && !App::wnd()->layerShown()) { diff --git a/Telegram/SourceFiles/pspecific_mac.cpp b/Telegram/SourceFiles/pspecific_mac.cpp index dedd5c33f..9719f72ee 100644 --- a/Telegram/SourceFiles/pspecific_mac.cpp +++ b/Telegram/SourceFiles/pspecific_mac.cpp @@ -84,7 +84,7 @@ void MacPrivate::notifyClicked(unsigned long long peer, int msgid) { void MacPrivate::notifyReplied(unsigned long long peer, int msgid, const char *str) { History *history = App::history(PeerId(peer)); - App::main()->sendMessage(history, QString::fromUtf8(str), (msgid > 0 && history->peer->chat) ? msgid : 0); + App::main()->sendMessage(history, QString::fromUtf8(str), (msgid > 0 && history->peer->chat) ? msgid : 0, false); } PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent), diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 9c05915c3..720a64fee 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -382,11 +382,27 @@ uint64 PtsWaiter::ptsKey(PtsSkippedQueue queue) { return _queue.insert(uint64(uint32(_last)) << 32 | uint64(uint32(_count)), queue).key(); } -void PtsWaiter::applySkippedUpdates(ChannelData *channel) { - if (!App::main()) return; - App::main()->ptsWaiterStartTimerFor(channel, -1); +void PtsWaiter::setWaitingForSkipped(ChannelData *channel, bool waiting) { + _waitingForSkipped = waiting; + checkForWaiting(channel); +} + +void PtsWaiter::setWaitingForShortPoll(ChannelData *channel, bool waiting) { + _waitingForShortPoll = waiting; + checkForWaiting(channel); +} + +void PtsWaiter::checkForWaiting(ChannelData *channel) { + if (!_waitingForSkipped && !_waitingForShortPoll && App::main()) { + App::main()->ptsWaiterStartTimerFor(channel, -1); + } +} + +void PtsWaiter::applySkippedUpdates(ChannelData *channel) { + setWaitingForSkipped(channel, false); + + if (!App::main() || _queue.isEmpty()) return; - if (_queue.isEmpty()) return; ++_applySkippedLevel; for (QMap::const_iterator i = _queue.cbegin(), e = _queue.cend(); i != e; ++i) { switch (i.value()) { diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index e679a6098..722a7f248 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -86,22 +86,27 @@ inline MTPpeer peerToMTP(const PeerId &id) { } return MTP_peerUser(MTP_int(0)); } -inline PeerId peerFromMessage(const MTPmessage &msg, int32 *msgFlags = 0) { +inline PeerId peerFromMessage(const MTPmessage &msg) { PeerId from_id = 0, to_id = 0; switch (msg.type()) { case mtpc_message: from_id = msg.c_message().has_from_id() ? peerFromUser(msg.c_message().vfrom_id) : 0; to_id = peerFromMTP(msg.c_message().vto_id); - if (msgFlags) *msgFlags = msg.c_message().vflags.v; break; case mtpc_messageService: from_id = msg.c_messageService().has_from_id() ? peerFromUser(msg.c_messageService().vfrom_id) : 0; to_id = peerFromMTP(msg.c_messageService().vto_id); - if (msgFlags) *msgFlags = msg.c_messageService().vflags.v; break; } return (from_id && peerToUser(to_id) == MTP::authedId()) ? from_id : to_id; } +inline int32 flagsFromMessage(const MTPmessage &msg) { + switch (msg.type()) { + case mtpc_message: return msg.c_message().vflags.v; + case mtpc_messageService: return msg.c_messageService().vflags.v; + } + return 0; +} typedef uint64 PhotoId; typedef uint64 VideoId; @@ -379,7 +384,14 @@ enum PtsSkippedQueue { class PtsWaiter { public: - PtsWaiter() : _good(0), _last(0), _count(0), _applySkippedLevel(0), _requesting(false) { + PtsWaiter() : + _good(0), + _last(0), + _count(0), + _applySkippedLevel(0), + _requesting(false), + _waitingForSkipped(false), + _waitingForShortPoll(false) { } void init(int32 pts) { _good = _last = _count = pts; @@ -394,6 +406,14 @@ public: bool requesting() const { return _requesting; } + bool waitingForSkipped() const { + return _waitingForSkipped; + } + bool waitingForShortPoll() const { + return _waitingForShortPoll; + } + void setWaitingForSkipped(ChannelData *channel, bool waiting); + void setWaitingForShortPoll(ChannelData *channel, bool waiting); int32 current() const{ return _good; } @@ -405,12 +425,13 @@ public: private: uint64 ptsKey(PtsSkippedQueue queue); + void checkForWaiting(ChannelData *channel); QMap _queue; QMap _updateQueue; QMap _updatesQueue; int32 _good, _last, _count; int32 _applySkippedLevel; - bool _requesting; + bool _requesting, _waitingForSkipped, _waitingForShortPoll; }; class ChannelData : public PeerData { @@ -465,6 +486,9 @@ public: void ptsClearSkippedUpdates() { return _ptsWaiter.clearSkippedUpdates(); } + void ptsWaitingForShortPoll(bool waiting) { + return _ptsWaiter.setWaitingForShortPoll(this, waiting); + } private: diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index bfa319ccd..315e8b847 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -586,21 +586,21 @@ void Window::getNotifySetting(const MTPInputNotifyPeer &peer, uint32 msWait) { MTP::send(MTPaccount_GetNotifySettings(peer), main->rpcDone(&MainWidget::gotNotifySetting, peer), main->rpcFail(&MainWidget::failNotifySetting, peer), 0, msWait); } -void Window::serviceNotification(const QString &msg, bool unread, const MTPMessageMedia &media, bool force) { +void Window::serviceNotification(const QString &msg, const MTPMessageMedia &media, bool force) { History *h = (main && App::userLoaded(ServiceUserId)) ? App::history(ServiceUserId) : 0; if (!h || (!force && h->isEmpty())) { - _delayedServiceMsgs.push_back(DelayedServiceMsg(qMakePair(msg, media), unread)); + _delayedServiceMsgs.push_back(DelayedServiceMsg(msg, media)); return sendServiceHistoryRequest(); } - main->serviceNotification(msg, media, unread); + main->serviceNotification(msg, media); } void Window::showDelayedServiceMsgs() { QVector toAdd = _delayedServiceMsgs; _delayedServiceMsgs.clear(); for (QVector::const_iterator i = toAdd.cbegin(), e = toAdd.cend(); i != e; ++i) { - serviceNotification(i->first.first, i->second, i->first.second, true); + serviceNotification(i->first, i->second, true); } } diff --git a/Telegram/SourceFiles/window.h b/Telegram/SourceFiles/window.h index a63c6044c..a25269a6d 100644 --- a/Telegram/SourceFiles/window.h +++ b/Telegram/SourceFiles/window.h @@ -151,7 +151,7 @@ public: void setupIntro(bool anim); void setupMain(bool anim, const MTPUser *user = 0); void getNotifySetting(const MTPInputNotifyPeer &peer, uint32 msWait = 0); - void serviceNotification(const QString &msg, bool unread = true, const MTPMessageMedia &media = MTP_messageMediaEmpty(), bool force = false); + void serviceNotification(const QString &msg, const MTPMessageMedia &media = MTP_messageMediaEmpty(), bool force = false); void sendServiceHistoryRequest(); void showDelayedServiceMsgs(); @@ -288,7 +288,7 @@ private: QWidget *centralwidget; - typedef QPair, bool> DelayedServiceMsg; + typedef QPair DelayedServiceMsg; QVector _delayedServiceMsgs; mtpRequestId _serviceHistoryRequest;