mirror of https://github.com/procxx/kepka.git
				
				
				
			comments show-hide in channels
This commit is contained in:
		
							parent
							
								
									ab7a745a49
								
							
						
					
					
						commit
						56a63a5b10
					
				| 
						 | 
				
			
			@ -456,8 +456,9 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
 | 
			
		|||
"lng_action_changed_title_channel" = "Channel name was changed to «{title}»";
 | 
			
		||||
"lng_action_created_chat" = "{from} created group «{title}»";
 | 
			
		||||
"lng_action_created_channel" = "Channel «{title}» created";
 | 
			
		||||
"lng_action_comments_disabled" = "Comments were disabled";
 | 
			
		||||
"lng_action_comments_enabled" = "Comments were enabled";
 | 
			
		||||
 | 
			
		||||
"lng_channel_comments_count" = "{count:_not_used_|# comment|# comments}";
 | 
			
		||||
"lng_channel_hide_comments" = "Hide comments";
 | 
			
		||||
 | 
			
		||||
"lng_group_invite_bad_link" = "This invite link is broken\nor has expired.";
 | 
			
		||||
"lng_group_invite_want_join" = "Do you want to join the group «{title}»?";
 | 
			
		||||
| 
						 | 
				
			
			@ -654,6 +655,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
 | 
			
		|||
"lng_try_other_contact" = "Try other";
 | 
			
		||||
"lng_contacts_done" = "Close";
 | 
			
		||||
"lng_create_group_link" = "Link";
 | 
			
		||||
"lng_create_group_invite_link" = "Invite link";
 | 
			
		||||
"lng_create_group_photo" = "Set Photo";
 | 
			
		||||
"lng_create_group_description" = "Description (optional)";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -909,6 +909,24 @@ msgDateImgCheckSpace: 4px;
 | 
			
		|||
msgDogImg: sprite(213px, 93px, 126px, 126px);
 | 
			
		||||
historyPadding: 10px;
 | 
			
		||||
 | 
			
		||||
collapseButton: flatButton(btnDefFlat) {
 | 
			
		||||
	font: msgServiceFont;
 | 
			
		||||
	overFont: msgServiceFont;
 | 
			
		||||
	width: -24px;
 | 
			
		||||
	bgColor: transparent;
 | 
			
		||||
	downBgColor: transparent;
 | 
			
		||||
	overBgColor: transparent;
 | 
			
		||||
	color: white;
 | 
			
		||||
	overColor: white;
 | 
			
		||||
	downColor: white;
 | 
			
		||||
	textTop: 3px;
 | 
			
		||||
	overTextTop: 3px;
 | 
			
		||||
	downTextTop: 3px;
 | 
			
		||||
	height: 24px;
 | 
			
		||||
}
 | 
			
		||||
collapseHideDuration: 200;
 | 
			
		||||
collapseShowDuration: 200;
 | 
			
		||||
 | 
			
		||||
defaultTextStyle: textStyle {
 | 
			
		||||
	lnkFlags: font(fsize);
 | 
			
		||||
	lnkOverFlags: font(fsize underline);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -168,7 +168,10 @@ void ApiWrap::gotReplyTo(ChannelData *channel, const MTPmessages_Messages &msgs,
 | 
			
		|||
		if (channel) {
 | 
			
		||||
			channel->ptsReceived(d.vpts.v);
 | 
			
		||||
		} else {
 | 
			
		||||
			LOG(("App Error: received messages.channelMessages in ApiWrap::gotReplyTo when no channel was passed!"));
 | 
			
		||||
			LOG(("App Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotReplyTo)"));
 | 
			
		||||
		}
 | 
			
		||||
		if (d.has_collapsed()) { // should not be returned
 | 
			
		||||
			LOG(("API Error: channels.getMessages and messages.getMessages should not return collapsed groups! (ApiWrap::gotReplyTo)"));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
| 
						 | 
				
			
			@ -619,7 +622,10 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
 | 
			
		|||
		if (channel) {
 | 
			
		||||
			channel->ptsReceived(d.vpts.v);
 | 
			
		||||
		} else {
 | 
			
		||||
			LOG(("App Error: received messages.channelMessages in ApiWrap::gotWebPages when no channel was passed!"));
 | 
			
		||||
			LOG(("API Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotWebPages)"));
 | 
			
		||||
		}
 | 
			
		||||
		if (d.has_collapsed()) { // should not be returned
 | 
			
		||||
			LOG(("API Error: channels.getMessages and messages.getMessages should not return collapsed groups! (ApiWrap::gotWebPages)"));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
| 
						 | 
				
			
			@ -641,7 +647,7 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
 | 
			
		|||
 | 
			
		||||
	MainWidget *m = App::main();
 | 
			
		||||
	for (QMap<uint64, int32>::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) {
 | 
			
		||||
		HistoryItem *item = App::histories().addToBack(v->at(i.value()), -1);
 | 
			
		||||
		HistoryItem *item = App::histories().addNewMessage(v->at(i.value()), -1);
 | 
			
		||||
		if (item) {
 | 
			
		||||
			item->initDimensions();
 | 
			
		||||
			if (m) m->itemResized(item);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -784,7 +784,7 @@ namespace App {
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for (QMap<uint64, int32>::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) {
 | 
			
		||||
			histories().addToBack(v.at(i.value()), msgsState);
 | 
			
		||||
			histories().addNewMessage(v.at(i.value()), msgsState);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -871,19 +871,30 @@ namespace App {
 | 
			
		|||
		MsgsData *data = fetchMsgsData(channelId, false);
 | 
			
		||||
		if (!data) return;
 | 
			
		||||
 | 
			
		||||
		ChannelHistory *channelHistory = (channelId == NoChannel) ? 0 : App::historyLoaded(peerFromChannel(channelId))->asChannelHistory();
 | 
			
		||||
 | 
			
		||||
		QMap<History*, bool> historiesToCheck;
 | 
			
		||||
		for (QVector<MTPint>::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) {
 | 
			
		||||
			MsgsData::const_iterator j = data->constFind(i->v);
 | 
			
		||||
			if (j != data->cend()) {
 | 
			
		||||
				History *h = (*j)->history();
 | 
			
		||||
				(*j)->destroy();
 | 
			
		||||
				if (App::main() && h->peer == App::main()->peer()) {
 | 
			
		||||
				if (App::main() && h->peer == App::main()->peer() && !(*j)->detached()) {
 | 
			
		||||
					resized = true;
 | 
			
		||||
				}
 | 
			
		||||
				(*j)->destroy();
 | 
			
		||||
				if (!h->lastMsg) historiesToCheck.insert(h, true);
 | 
			
		||||
			} else if (channelHistory) {
 | 
			
		||||
				channelHistory->messageWithIdDeleted(i->v);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (resized) {
 | 
			
		||||
			App::main()->itemResized(0);
 | 
			
		||||
		}
 | 
			
		||||
		if (main()) {
 | 
			
		||||
			for (QMap<History*, bool>::const_iterator i = historiesToCheck.cbegin(), e = historiesToCheck.cend(); i != e; ++i) {
 | 
			
		||||
				main()->checkPeerHistory(i.key()->peer);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void feedUserLinks(const MTPVector<MTPcontacts_Link> &links, bool emitPeerUpdated) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1630,26 +1641,15 @@ namespace App {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	History *history(const PeerId &peer) {
 | 
			
		||||
		Histories::const_iterator i = ::histories.constFind(peer);
 | 
			
		||||
		if (i == ::histories.cend()) {
 | 
			
		||||
			i = App::histories().insert(peer, new History(peer));
 | 
			
		||||
		}
 | 
			
		||||
		return i.value();
 | 
			
		||||
		return ::histories.findOrInsert(peer, 0, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	History *historyFromDialog(const PeerId &peer, int32 unreadCnt, int32 maxInboxRead) {
 | 
			
		||||
		Histories::const_iterator i = ::histories.constFind(peer);
 | 
			
		||||
		if (i == ::histories.cend()) {
 | 
			
		||||
			i = App::histories().insert(peer, new History(peer));
 | 
			
		||||
			i.value()->setUnreadCount(unreadCnt, false);
 | 
			
		||||
			i.value()->inboxReadBefore = maxInboxRead + 1;
 | 
			
		||||
		}
 | 
			
		||||
		return i.value();
 | 
			
		||||
		return ::histories.findOrInsert(peer, unreadCnt, maxInboxRead);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	History *historyLoaded(const PeerId &peer) {
 | 
			
		||||
		Histories::const_iterator i = ::histories.constFind(peer);
 | 
			
		||||
		return (i == ::histories.cend()) ? 0 : i.value();
 | 
			
		||||
		return ::histories.find(peer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	HistoryItem *histItemById(ChannelId channelId, MsgId itemId) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2406,7 +2406,7 @@ namespace App {
 | 
			
		|||
		return ::corners[index];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void roundRect(QPainter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, RoundCorners index, const style::color *sh) {
 | 
			
		||||
	void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, RoundCorners index, const style::color *sh) {
 | 
			
		||||
		QPixmap **c = ::corners[index];
 | 
			
		||||
		int32 cw = c[0]->width() / cIntRetinaFactor(), ch = c[0]->height() / cIntRetinaFactor();
 | 
			
		||||
		if (w < 2 * cw || h < 2 * ch) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -2424,7 +2424,7 @@ namespace App {
 | 
			
		|||
		p.drawPixmap(QPoint(x + w - cw, y + h - ch), *c[3]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void roundShadow(QPainter &p, int32 x, int32 y, int32 w, int32 h, const style::color &sh, RoundCorners index) {
 | 
			
		||||
	void roundShadow(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &sh, RoundCorners index) {
 | 
			
		||||
		QPixmap **c = App::corners(index);
 | 
			
		||||
		int32 cw = c[0]->width() / cIntRetinaFactor(), ch = c[0]->height() / cIntRetinaFactor();
 | 
			
		||||
		p.fillRect(x + cw, y + h, w - 2 * cw, st::msgShadow, sh->b);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -261,12 +261,12 @@ namespace App {
 | 
			
		|||
 | 
			
		||||
	QImage **cornersMask();
 | 
			
		||||
	QPixmap **corners(RoundCorners index);
 | 
			
		||||
	void roundRect(QPainter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, RoundCorners index, const style::color *sh = 0);
 | 
			
		||||
	inline void roundRect(QPainter &p, const QRect &rect, const style::color &bg, RoundCorners index, const style::color *sh = 0) {
 | 
			
		||||
	void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, RoundCorners index, const style::color *sh = 0);
 | 
			
		||||
	inline void roundRect(Painter &p, const QRect &rect, const style::color &bg, RoundCorners index, const style::color *sh = 0) {
 | 
			
		||||
		return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, index, sh);
 | 
			
		||||
	}
 | 
			
		||||
	void roundShadow(QPainter &p, int32 x, int32 y, int32 w, int32 h, const style::color &sh, RoundCorners index);
 | 
			
		||||
	inline void roundShadow(QPainter &p, const QRect &rect, const style::color &sh, RoundCorners index) {
 | 
			
		||||
	void roundShadow(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &sh, RoundCorners index);
 | 
			
		||||
	inline void roundShadow(Painter &p, const QRect &rect, const style::color &sh, RoundCorners index) {
 | 
			
		||||
		return roundShadow(p, rect.x(), rect.y(), rect.width(), rect.height(), sh, index);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -207,7 +207,7 @@ ContactsInner::ContactData *ContactsInner::contactData(DialogRow *row) {
 | 
			
		|||
					data->online = lng_chat_status_members(lt_count, chat->count);
 | 
			
		||||
				}
 | 
			
		||||
			} else if (peer->isChannel()) {
 | 
			
		||||
				data->online = lang(lng_chat_status_unaccessible); // CHANNELS_UX
 | 
			
		||||
				data->online = lang(lng_channel_status);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			data = i.value();
 | 
			
		||||
| 
						 | 
				
			
			@ -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(MTPmessages_CreateChannel_flag_broadcast), MTP_string(name), MTP_string(_description.getLastText().trimmed()), MTP_vector<MTPInputUser>(0)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail));
 | 
			
		||||
		_creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(0), MTP_string(name), MTP_string(_description.getLastText().trimmed()), MTP_vector<MTPInputUser>(0)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1804,7 +1804,7 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) {
 | 
			
		|||
 | 
			
		||||
	p.setPen(st::black);
 | 
			
		||||
	p.setFont(st::newGroupLinkFont);
 | 
			
		||||
	p.drawTextLeft(st::newGroupPadding.left(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop, width(), lang(lng_create_group_link));
 | 
			
		||||
	p.drawTextLeft(st::newGroupPadding.left(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop, width(), lang(_link.isHidden() ? lng_create_group_invite_link : lng_create_group_link));
 | 
			
		||||
 | 
			
		||||
	if (_link.isHidden()) {
 | 
			
		||||
		QTextOption option(style::al_left);
 | 
			
		||||
| 
						 | 
				
			
			@ -1899,8 +1899,8 @@ void SetupChannelBox::closePressed() {
 | 
			
		|||
 | 
			
		||||
void SetupChannelBox::onSave() {
 | 
			
		||||
	if (!_public.checked()) {
 | 
			
		||||
		if (_comments.checked()) {
 | 
			
		||||
			MTP::send(MTPchannels_ToggleComments(_channel->inputChannel, MTP_bool(true)));
 | 
			
		||||
		if (!_comments.checked()) {
 | 
			
		||||
			MTP::send(MTPchannels_ToggleComments(_channel->inputChannel, MTP_bool(false)));
 | 
			
		||||
		}
 | 
			
		||||
		onClose();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -124,7 +124,7 @@ void PhotoSendBox::keyPressEvent(QKeyEvent *e) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void PhotoSendBox::paintEvent(QPaintEvent *e) {
 | 
			
		||||
	QPainter p(this);
 | 
			
		||||
	Painter p(this);
 | 
			
		||||
	if (paint(p)) return;
 | 
			
		||||
 | 
			
		||||
	// paint shadow
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -123,7 +123,7 @@ enum {
 | 
			
		|||
	MaxUsernameLength = 32,
 | 
			
		||||
	UsernameCheckTimeout = 200,
 | 
			
		||||
 | 
			
		||||
	MaxChannelDescription = 255,
 | 
			
		||||
	MaxChannelDescription = 120,
 | 
			
		||||
 | 
			
		||||
	MaxMessageSize = 4096,
 | 
			
		||||
	MaxHttpRedirects = 5, // when getting external data/images
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -779,8 +779,10 @@ void DialogsListWidget::dialogsReceived(const QVector<MTPDialog> &added) {
 | 
			
		|||
			const MTPDdialogChannel &d(i->c_dialogChannel());
 | 
			
		||||
			History *history = App::historyFromDialog(peerFromMTP(d.vpeer), d.vunread_important_count.v, d.vread_inbox_max_id.v);
 | 
			
		||||
			if (history->peer->isChannel()) {
 | 
			
		||||
				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();
 | 
			
		||||
			App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, history);
 | 
			
		||||
		} break;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -821,7 +823,7 @@ void DialogsListWidget::searchReceived(const QVector<MTPMessage> &messages, bool
 | 
			
		|||
		clearSearchResults(false);
 | 
			
		||||
	}
 | 
			
		||||
	for (QVector<MTPMessage>::const_iterator i = messages.cbegin(), e = messages.cend(); i != e; ++i) {
 | 
			
		||||
		HistoryItem *item = App::histories().addToBack(*i, -1);
 | 
			
		||||
		HistoryItem *item = App::histories().addNewMessage(*i, -1);
 | 
			
		||||
		searchResults.push_back(new FakeDialogRow(item));
 | 
			
		||||
		_lastSearchId = item->id;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1602,26 +1604,28 @@ void DialogsWidget::unreadCountsReceived(const QVector<MTPDialog> &dialogs) {
 | 
			
		|||
		switch (i->type()) {
 | 
			
		||||
		case mtpc_dialog: {
 | 
			
		||||
			const MTPDdialog &d(i->c_dialog());
 | 
			
		||||
			Histories::iterator j = App::histories().find(peerFromMTP(d.vpeer));
 | 
			
		||||
			if (j != App::histories().end()) {
 | 
			
		||||
				App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, j.value());
 | 
			
		||||
				if (d.vunread_count.v >= j.value()->unreadCount) {
 | 
			
		||||
					j.value()->setUnreadCount(d.vunread_count.v, false);
 | 
			
		||||
					j.value()->inboxReadBefore = d.vread_inbox_max_id.v + 1;
 | 
			
		||||
			if (History *h = App::historyLoaded(peerFromMTP(d.vpeer))) {
 | 
			
		||||
				App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, h);
 | 
			
		||||
				if (d.vunread_count.v >= h->unreadCount) {
 | 
			
		||||
					h->setUnreadCount(d.vunread_count.v, false);
 | 
			
		||||
					h->inboxReadBefore = d.vread_inbox_max_id.v + 1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} break;
 | 
			
		||||
		case mtpc_dialogChannel: {
 | 
			
		||||
			const MTPDdialogChannel &d(i->c_dialogChannel());
 | 
			
		||||
			Histories::iterator j = App::histories().find(peerFromMTP(d.vpeer));
 | 
			
		||||
			if (j != App::histories().end()) {
 | 
			
		||||
				if (j.value()->peer->isChannel()) {
 | 
			
		||||
					j.value()->peer->asChannel()->ptsReceived(d.vpts.v);
 | 
			
		||||
			if (History *h = App::historyLoaded(peerFromMTP(d.vpeer))) {
 | 
			
		||||
				if (h->peer->isChannel()) {
 | 
			
		||||
					h->peer->asChannel()->ptsReceived(d.vpts.v);
 | 
			
		||||
					if (d.vunread_count.v >= h->asChannelHistory()->unreadCountAll) {
 | 
			
		||||
						h->asChannelHistory()->unreadCountAll = d.vunread_count.v;
 | 
			
		||||
						h->inboxReadBefore = d.vread_inbox_max_id.v + 1;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, j.value());
 | 
			
		||||
				if (d.vunread_important_count.v >= j.value()->unreadCount) {
 | 
			
		||||
					j.value()->setUnreadCount(d.vunread_important_count.v, false);
 | 
			
		||||
					j.value()->inboxReadBefore = d.vread_inbox_max_id.v + 1;
 | 
			
		||||
				App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, h);
 | 
			
		||||
				if (d.vunread_important_count.v >= h->unreadCount) {
 | 
			
		||||
					h->setUnreadCount(d.vunread_important_count.v, false);
 | 
			
		||||
					h->inboxReadBefore = d.vread_inbox_max_id.v + 1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1863,7 +1867,10 @@ void DialogsWidget::searchReceived(bool fromStart, const MTPmessages_Messages &r
 | 
			
		|||
			if (_searchInPeer && _searchInPeer->isChannel()) {
 | 
			
		||||
				_searchInPeer->asChannel()->ptsReceived(d.vpts.v);
 | 
			
		||||
			} else {
 | 
			
		||||
				LOG(("App Error: received messages.channelMessages in DialogsWidget::searchReceived when no channel was passed!"));
 | 
			
		||||
				LOG(("API Error: received messages.channelMessages when no channel was passed! (DialogsWidget::searchReceived)"));
 | 
			
		||||
			}
 | 
			
		||||
			if (d.has_collapsed()) { // should not be returned
 | 
			
		||||
				LOG(("API Error: channels.getMessages and messages.getMessages should not return collapsed groups! (DialogsWidget::searchReceived)"));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			App::feedUsers(d.vusers);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,6 +37,10 @@ void FlatButton::setOpacity(float64 o) {
 | 
			
		|||
	update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float64 FlatButton::opacity() const {
 | 
			
		||||
	return _opacity;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FlatButton::setText(const QString &text) {
 | 
			
		||||
	_text = text;
 | 
			
		||||
	update();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ public:
 | 
			
		|||
	bool animStep(float64 ms);
 | 
			
		||||
	void paintEvent(QPaintEvent *e);
 | 
			
		||||
	void setOpacity(float64 o);
 | 
			
		||||
	float64 opacity() const;
 | 
			
		||||
 | 
			
		||||
	void setText(const QString &text);
 | 
			
		||||
	void setWidth(int32 w);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -34,9 +34,11 @@ extern TextParseOptions _textNameOptions, _textDlgOptions, _historyTextOptions,
 | 
			
		|||
 | 
			
		||||
#include "structs.h"
 | 
			
		||||
 | 
			
		||||
struct History;
 | 
			
		||||
struct Histories : public QHash<PeerId, History*>, public Animated {
 | 
			
		||||
	typedef QHash<PeerId, History*> Parent;
 | 
			
		||||
class History;
 | 
			
		||||
class Histories : public Animated {
 | 
			
		||||
public:
 | 
			
		||||
	typedef QHash<PeerId, History*> Map;
 | 
			
		||||
	Map map;
 | 
			
		||||
 | 
			
		||||
	Histories() : unreadFull(0), unreadMuted(0) {
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -44,16 +46,17 @@ struct Histories : public QHash<PeerId, History*>, public Animated {
 | 
			
		|||
	void regSendAction(History *history, UserData *user, const MTPSendMessageAction &action);
 | 
			
		||||
	bool animStep(float64 ms);
 | 
			
		||||
 | 
			
		||||
	History *find(const PeerId &peerId);
 | 
			
		||||
	History *findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead);
 | 
			
		||||
 | 
			
		||||
	void clear();
 | 
			
		||||
	Parent::iterator erase(Parent::iterator i);
 | 
			
		||||
	void remove(const PeerId &peer);
 | 
			
		||||
	~Histories() {
 | 
			
		||||
		clear();
 | 
			
		||||
 | 
			
		||||
		unreadFull = unreadMuted = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	HistoryItem *addToBack(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, int msgState = 1); // 2 - new read message, 1 - new unread message, 0 - not new message, -1 - searched message
 | 
			
		||||
	//	HistoryItem *addToBack(const MTPgeoChatMessage &msg, bool newMsg = true);
 | 
			
		||||
 | 
			
		||||
	typedef QMap<History*, uint64> TypingHistories; // when typing in this history started
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +65,7 @@ struct Histories : public QHash<PeerId, History*>, public Animated {
 | 
			
		|||
	int32 unreadFull, unreadMuted;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct HistoryBlock;
 | 
			
		||||
class HistoryBlock;
 | 
			
		||||
 | 
			
		||||
struct DialogRow {
 | 
			
		||||
	DialogRow(History *history = 0, DialogRow *prev = 0, DialogRow *next = 0, int32 pos = 0) : prev(prev), next(next), history(history), pos(pos), attached(0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -158,19 +161,29 @@ struct SendAction {
 | 
			
		|||
class HistoryMedia;
 | 
			
		||||
class HistoryMessage;
 | 
			
		||||
class HistoryUnreadBar;
 | 
			
		||||
struct History : public QList<HistoryBlock*> {
 | 
			
		||||
 | 
			
		||||
class ChannelHistory;
 | 
			
		||||
class History {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	History(const PeerId &peerId);
 | 
			
		||||
	ChannelId channelId() const {
 | 
			
		||||
		return peerToChannel(peer->id);
 | 
			
		||||
	}
 | 
			
		||||
	bool isChannel() const {
 | 
			
		||||
		return peerIsChannel(peer->id);
 | 
			
		||||
	}
 | 
			
		||||
	ChannelHistory *asChannelHistory();
 | 
			
		||||
	const ChannelHistory *asChannelHistory() const;
 | 
			
		||||
 | 
			
		||||
	typedef QList<HistoryBlock*> Parent;
 | 
			
		||||
	bool isEmpty() const {
 | 
			
		||||
		return blocks.isEmpty();
 | 
			
		||||
	}
 | 
			
		||||
	void clear(bool leaveItems = false);
 | 
			
		||||
	Parent::iterator erase(Parent::iterator i);
 | 
			
		||||
	void blockResized(HistoryBlock *block, int32 dh);
 | 
			
		||||
	void removeBlock(HistoryBlock *block);
 | 
			
		||||
 | 
			
		||||
	~History() {
 | 
			
		||||
	virtual ~History() {
 | 
			
		||||
		clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -178,16 +191,14 @@ struct History : public QList<HistoryBlock*> {
 | 
			
		|||
	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 *addToBackService(MsgId msgId, QDateTime date, const QString &text, int32 flags = 0, HistoryMedia *media = 0, bool newMsg = true);
 | 
			
		||||
	HistoryItem *addToBack(const MTPmessage &msg, bool newMsg = true);
 | 
			
		||||
	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 *addToHistory(const MTPmessage &msg);
 | 
			
		||||
	HistoryItem *addToBackForwarded(MsgId id, QDateTime date, int32 from, HistoryMessage *item);
 | 
			
		||||
	HistoryItem *addToBackDocument(MsgId id, int32 flags, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc);
 | 
			
		||||
	HistoryItem *addNewForwarded(MsgId id, QDateTime date, int32 from, HistoryMessage *item);
 | 
			
		||||
	HistoryItem *addNewDocument(MsgId id, int32 flags, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc);
 | 
			
		||||
 | 
			
		||||
	void addToFront(const QVector<MTPMessage> &slice);
 | 
			
		||||
	void addToBack(const QVector<MTPMessage> &slice);
 | 
			
		||||
	void createInitialDateBlock(const QDateTime &date);
 | 
			
		||||
	HistoryItem *doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg);
 | 
			
		||||
	void addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPMessageGroup> *collapsed);
 | 
			
		||||
	void addNewerSlice(const QVector<MTPMessage> &slice, const QVector<MTPMessageGroup> *collapsed);
 | 
			
		||||
	void addToOverview(HistoryItem *item, MediaOverviewType type);
 | 
			
		||||
	bool addToOverviewFront(HistoryItem *item, MediaOverviewType type);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -195,6 +206,7 @@ struct History : public QList<HistoryBlock*> {
 | 
			
		|||
	void unregTyping(UserData *from);
 | 
			
		||||
 | 
			
		||||
	int32 countUnread(MsgId upTo);
 | 
			
		||||
	void updateShowFrom();
 | 
			
		||||
	MsgId inboxRead(MsgId upTo);
 | 
			
		||||
	MsgId inboxRead(HistoryItem *wasRead);
 | 
			
		||||
	MsgId outboxRead(MsgId upTo);
 | 
			
		||||
| 
						 | 
				
			
			@ -210,8 +222,8 @@ struct History : public QList<HistoryBlock*> {
 | 
			
		|||
	bool loadedAtBottom() const; // last message is in the list
 | 
			
		||||
	void setNotLoadedAtBottom();
 | 
			
		||||
	bool loadedAtTop() const; // nothing was added after loading history back
 | 
			
		||||
	bool isReadyFor(MsgId msgId, bool check = false) const; // has messages for showing history at msgId
 | 
			
		||||
	void getReadyFor(MsgId msgId);
 | 
			
		||||
	bool isReadyFor(MsgId msgId, MsgId &fixInScrollMsgId, int32 &fixInScrollMsgTop); // has messages for showing history at msgId
 | 
			
		||||
	void getReadyFor(MsgId msgId, MsgId &fixInScrollMsgId, int32 &fixInScrollMsgTop);
 | 
			
		||||
 | 
			
		||||
	void setLastMessage(HistoryItem *msg, bool updatePosInDialogs = true);
 | 
			
		||||
	void setPosInDialogsDate(const QDateTime &date);
 | 
			
		||||
| 
						 | 
				
			
			@ -222,18 +234,6 @@ struct History : public QList<HistoryBlock*> {
 | 
			
		|||
	MsgId msgIdForRead() const;
 | 
			
		||||
 | 
			
		||||
	int32 geomResize(int32 newWidth, int32 *ytransform = 0, HistoryItem *resizedItem = 0); // return new size
 | 
			
		||||
	int32 width, height, msgCount, unreadCount;
 | 
			
		||||
	int32 inboxReadBefore, outboxReadBefore;
 | 
			
		||||
	HistoryItem *showFrom;
 | 
			
		||||
	HistoryUnreadBar *unreadBar;
 | 
			
		||||
 | 
			
		||||
	PeerData *peer;
 | 
			
		||||
	bool oldLoaded, newLoaded;
 | 
			
		||||
	HistoryItem *lastMsg;
 | 
			
		||||
	QDateTime lastMsgDate;
 | 
			
		||||
 | 
			
		||||
	typedef QList<HistoryItem*> NotifyQueue;
 | 
			
		||||
	NotifyQueue notifies;
 | 
			
		||||
 | 
			
		||||
	void removeNotification(HistoryItem *item) {
 | 
			
		||||
		if (!notifies.isEmpty()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -275,6 +275,27 @@ struct History : public QList<HistoryBlock*> {
 | 
			
		|||
		// showFrom can't be detached
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void paintDialog(Painter &p, int32 w, bool sel) const;
 | 
			
		||||
	void eraseFromOverview(MediaOverviewType type, MsgId msgId);
 | 
			
		||||
	bool updateTyping(uint64 ms = 0, uint32 dots = 0, bool force = false);
 | 
			
		||||
	void clearLastKeyboard();
 | 
			
		||||
 | 
			
		||||
	typedef QList<HistoryBlock*> Blocks;
 | 
			
		||||
	Blocks blocks;
 | 
			
		||||
 | 
			
		||||
	int32 width, height, msgCount, unreadCount;
 | 
			
		||||
	int32 inboxReadBefore, outboxReadBefore;
 | 
			
		||||
	HistoryItem *showFrom;
 | 
			
		||||
	HistoryUnreadBar *unreadBar;
 | 
			
		||||
 | 
			
		||||
	PeerData *peer;
 | 
			
		||||
	bool oldLoaded, newLoaded;
 | 
			
		||||
	HistoryItem *lastMsg;
 | 
			
		||||
	QDateTime lastMsgDate;
 | 
			
		||||
 | 
			
		||||
	typedef QList<HistoryItem*> NotifyQueue;
 | 
			
		||||
	NotifyQueue notifies;
 | 
			
		||||
 | 
			
		||||
	QString draft;
 | 
			
		||||
	MsgId draftToId;
 | 
			
		||||
	MessageCursor draftCursor;
 | 
			
		||||
| 
						 | 
				
			
			@ -286,15 +307,12 @@ struct History : public QList<HistoryBlock*> {
 | 
			
		|||
	bool lastKeyboardInited, lastKeyboardUsed;
 | 
			
		||||
	MsgId lastKeyboardId;
 | 
			
		||||
	PeerId lastKeyboardFrom;
 | 
			
		||||
	void clearLastKeyboard();
 | 
			
		||||
 | 
			
		||||
	mtpRequestId sendRequestId;
 | 
			
		||||
 | 
			
		||||
	mutable const HistoryItem *textCachedFor; // cache
 | 
			
		||||
	mutable Text lastItemTextCache;
 | 
			
		||||
 | 
			
		||||
	void paintDialog(Painter &p, int32 w, bool sel) const;
 | 
			
		||||
 | 
			
		||||
	typedef QMap<QChar, DialogRow*> DialogLinks;
 | 
			
		||||
	DialogLinks dialogs;
 | 
			
		||||
	uint64 posInDialogs; // like ((unixtime) << 32) | (incremented counter)
 | 
			
		||||
| 
						 | 
				
			
			@ -306,19 +324,71 @@ struct History : public QList<HistoryBlock*> {
 | 
			
		|||
	QString typingStr;
 | 
			
		||||
	Text typingText;
 | 
			
		||||
	uint32 typingFrame;
 | 
			
		||||
	bool updateTyping(uint64 ms = 0, uint32 dots = 0, bool force = false);
 | 
			
		||||
	QMap<SendActionType, uint64> mySendActions;
 | 
			
		||||
 | 
			
		||||
	typedef QList<MsgId> MediaOverview;
 | 
			
		||||
	typedef QMap<MsgId, NullType> MediaOverviewIds;
 | 
			
		||||
	MediaOverview overview[OverviewCount];
 | 
			
		||||
	MediaOverviewIds overviewIds[OverviewCount];
 | 
			
		||||
	int32 overviewCount[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
 | 
			
		||||
 | 
			
		||||
	MediaOverview _overview[OverviewCount];
 | 
			
		||||
	MediaOverviewIds _overviewIds[OverviewCount];
 | 
			
		||||
	int32 _overviewCount[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
	void eraseFromOverview(MediaOverviewType type, MsgId msgId);
 | 
			
		||||
	HistoryItem *addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, const QDateTime &date, HistoryItem *prev, HistoryBlock *block);
 | 
			
		||||
	HistoryItem *addNewItem(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
	void createInitialDateBlock(const QDateTime &date);
 | 
			
		||||
	HistoryItem *addItemAfterPrevToBlock(HistoryItem *item, HistoryItem *prev, HistoryBlock *block);
 | 
			
		||||
	HistoryItem *addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex);
 | 
			
		||||
 | 
			
		||||
	friend class HistoryBlock;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class HistoryGroup;
 | 
			
		||||
class HistoryCollapse;
 | 
			
		||||
class ChannelHistory : public History {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	ChannelHistory(const PeerId &peer);
 | 
			
		||||
 | 
			
		||||
	void messageDetached(HistoryItem *msg);
 | 
			
		||||
	void messageDeleted(HistoryItem *msg);
 | 
			
		||||
	void messageWithIdDeleted(MsgId msgId);
 | 
			
		||||
 | 
			
		||||
	bool isSwitchReadyFor(MsgId switchId, MsgId &fixInScrollMsgId, int32 &fixInScrollMsgTop); // has messages for showing history after switching mode at switchId
 | 
			
		||||
	void getSwitchReadyFor(MsgId switchId, MsgId &fixInScrollMsgId, int32 &fixInScrollMsgTop);
 | 
			
		||||
 | 
			
		||||
	void insertCollapseItem(MsgId wasMinId);
 | 
			
		||||
 | 
			
		||||
	int32 unreadCountAll;
 | 
			
		||||
	bool onlyImportant() const {
 | 
			
		||||
		return _onlyImportant;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	HistoryCollapse *collapse() const {
 | 
			
		||||
		return _collapse;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
	HistoryGroup *findGroup(MsgId msgId) const;
 | 
			
		||||
	HistoryBlock *findGroupBlock(MsgId msgId) const;
 | 
			
		||||
	HistoryGroup *findGroupInOther(MsgId msgId) const;
 | 
			
		||||
	HistoryItem *findPrevItem(HistoryItem *item) const;
 | 
			
		||||
	bool _onlyImportant;
 | 
			
		||||
 | 
			
		||||
	typedef QList<HistoryItem*> OtherList;
 | 
			
		||||
	OtherList _otherList;
 | 
			
		||||
	bool _otherOldLoaded, _otherNewLoaded;
 | 
			
		||||
	int32 _otherMsgCount;
 | 
			
		||||
 | 
			
		||||
	HistoryCollapse *_collapse;
 | 
			
		||||
 | 
			
		||||
	void switchMode();
 | 
			
		||||
 | 
			
		||||
	static const int32 ScrollMax = INT_MAX;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum DialogsSortMode {
 | 
			
		||||
| 
						 | 
				
			
			@ -596,13 +666,15 @@ struct DialogsIndexed {
 | 
			
		|||
	DialogsIndex index;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct HistoryBlock : public QVector<HistoryItem*> {
 | 
			
		||||
class HistoryBlock {
 | 
			
		||||
public:
 | 
			
		||||
	HistoryBlock(History *hist) : y(0), height(0), history(hist) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	typedef QVector<HistoryItem*> Parent;
 | 
			
		||||
	typedef QVector<HistoryItem*> Items;
 | 
			
		||||
	Items items;
 | 
			
		||||
 | 
			
		||||
	void clear(bool leaveItems = false);
 | 
			
		||||
	Parent::iterator erase(Parent::iterator i);
 | 
			
		||||
	~HistoryBlock() {
 | 
			
		||||
		clear();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -667,18 +739,25 @@ enum InfoDisplayType {
 | 
			
		|||
	InfoDisplayOverImage,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum HistoryItemType {
 | 
			
		||||
	HistoryItemMsg = 0,
 | 
			
		||||
	HistoryItemDate,
 | 
			
		||||
	HistoryItemUnreadBar,
 | 
			
		||||
	HistoryItemGroup,
 | 
			
		||||
	HistoryItemCollapse
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class HistoryMedia;
 | 
			
		||||
class HistoryItem : public HistoryElem {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	HistoryItem(History *history, HistoryBlock *block, MsgId msgId, int32 flags, QDateTime msgDate, int32 from);
 | 
			
		||||
 | 
			
		||||
	enum {
 | 
			
		||||
		MsgType = 0,
 | 
			
		||||
		DateType,
 | 
			
		||||
		UnreadBarType
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	virtual void initDimensions() = 0;
 | 
			
		||||
	virtual int32 resize(int32 width) = 0; // return new height
 | 
			
		||||
	virtual void draw(Painter &p, uint32 selection) const = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -732,6 +811,9 @@ public:
 | 
			
		|||
	bool fromChannel() const {
 | 
			
		||||
		return _from->isChannel();
 | 
			
		||||
	}
 | 
			
		||||
	bool isImportant() const {
 | 
			
		||||
		return _history->isChannel() && isImportantChannelMessage(_flags);
 | 
			
		||||
	}
 | 
			
		||||
	virtual bool needCheck() const {
 | 
			
		||||
		return out();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -750,8 +832,8 @@ public:
 | 
			
		|||
	virtual uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const {
 | 
			
		||||
		return (from << 16) | to;
 | 
			
		||||
	}
 | 
			
		||||
	virtual int32 itemType() const {
 | 
			
		||||
		return MsgType;
 | 
			
		||||
	virtual HistoryItemType type() const {
 | 
			
		||||
		return HistoryItemMsg;
 | 
			
		||||
	}
 | 
			
		||||
	virtual bool serviceMsg() const {
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -896,6 +978,18 @@ private:
 | 
			
		|||
	MsgId _msgid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class CommentsLink : public ITextLink {
 | 
			
		||||
	TEXT_LINK_CLASS(CommentsLink)
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	CommentsLink(HistoryItem *item) : _item(item) {
 | 
			
		||||
	}
 | 
			
		||||
	void onClick(Qt::MouseButton button) const;
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	HistoryItem *_item;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
HistoryItem *regItem(HistoryItem *item, bool returnExisting = false);
 | 
			
		||||
 | 
			
		||||
class HistoryMedia : public HistoryElem {
 | 
			
		||||
| 
						 | 
				
			
			@ -1596,6 +1690,8 @@ public:
 | 
			
		|||
		return _media ? _media->animating() : false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setText(const QString &text);
 | 
			
		||||
 | 
			
		||||
	~HistoryServiceMsg();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
| 
						 | 
				
			
			@ -1624,11 +1720,77 @@ public:
 | 
			
		|||
	QString selectedText(uint32 selection) const {
 | 
			
		||||
		return QString();
 | 
			
		||||
	}
 | 
			
		||||
	int32 itemType() const {
 | 
			
		||||
		return DateType;
 | 
			
		||||
	HistoryItemType type() const {
 | 
			
		||||
		return HistoryItemDate;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class HistoryGroup : public HistoryServiceMsg {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	HistoryGroup(History *history, HistoryBlock *block, const MTPDmessageGroup &group, 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;
 | 
			
		||||
		after = false;
 | 
			
		||||
		upon = false;
 | 
			
		||||
	}
 | 
			
		||||
	QString selectedText(uint32 selection) const {
 | 
			
		||||
		return QString();
 | 
			
		||||
	}
 | 
			
		||||
	HistoryItemType type() const {
 | 
			
		||||
		return HistoryItemGroup;
 | 
			
		||||
	}
 | 
			
		||||
	void uniteWith(MsgId minId, MsgId maxId, int32 count);
 | 
			
		||||
	void uniteWith(const HistoryGroup *other) {
 | 
			
		||||
		uniteWith(other->_minId, other->_maxId, other->_count);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool decrementCount(); // returns true if result count > 0
 | 
			
		||||
 | 
			
		||||
	MsgId minId() const {
 | 
			
		||||
		return _minId;
 | 
			
		||||
	}
 | 
			
		||||
	MsgId maxId() const {
 | 
			
		||||
		return _maxId;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	MsgId _minId, _maxId;
 | 
			
		||||
	int32 _count;
 | 
			
		||||
 | 
			
		||||
	TextLinkPtr _lnk;
 | 
			
		||||
 | 
			
		||||
	void updateText();
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class HistoryCollapse : public HistoryServiceMsg {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	HistoryCollapse(History *history, HistoryBlock *block, MsgId wasMinId, const QDateTime &date);
 | 
			
		||||
	void draw(Painter &p, uint32 selection) const;
 | 
			
		||||
	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;
 | 
			
		||||
		after = false;
 | 
			
		||||
		upon = false;
 | 
			
		||||
	}
 | 
			
		||||
	QString selectedText(uint32 selection) const {
 | 
			
		||||
		return QString();
 | 
			
		||||
	}
 | 
			
		||||
	HistoryItemType type() const {
 | 
			
		||||
		return HistoryItemCollapse;
 | 
			
		||||
	}
 | 
			
		||||
	MsgId wasMinId() const {
 | 
			
		||||
		return _wasMinId;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	MsgId _wasMinId;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
HistoryItem *createDayServiceMsg(History *history, HistoryBlock *block, QDateTime date);
 | 
			
		||||
 | 
			
		||||
class HistoryUnreadBar : public HistoryItem {
 | 
			
		||||
| 
						 | 
				
			
			@ -1649,8 +1811,8 @@ public:
 | 
			
		|||
	QString selectedText(uint32 selection) const {
 | 
			
		||||
		return QString();
 | 
			
		||||
	}
 | 
			
		||||
	int32 itemType() const {
 | 
			
		||||
		return UnreadBarType;
 | 
			
		||||
	HistoryItemType type() const {
 | 
			
		||||
		return HistoryItemUnreadBar;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,12 +82,12 @@ HistoryList::HistoryList(HistoryWidget *historyWidget, ScrollArea *scroll, Histo
 | 
			
		|||
	setMouseTracking(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryList::messagesReceived(const QVector<MTPMessage> &messages) {
 | 
			
		||||
	hist->addToFront(messages);
 | 
			
		||||
void HistoryList::messagesReceived(const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed) {
 | 
			
		||||
	hist->addOlderSlice(messages, collapsed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryList::messagesReceivedDown(const QVector<MTPMessage> &messages) {
 | 
			
		||||
	hist->addToBack(messages);
 | 
			
		||||
void HistoryList::messagesReceivedDown(const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed) {
 | 
			
		||||
	hist->addNewerSlice(messages, collapsed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryList::updateMsg(const HistoryItem *msg) {
 | 
			
		||||
| 
						 | 
				
			
			@ -123,8 +123,8 @@ void HistoryList::paintEvent(QPaintEvent *e) {
 | 
			
		|||
	}
 | 
			
		||||
	if (!_firstLoading && !hist->isEmpty()) {
 | 
			
		||||
		adjustCurrent(r.top());
 | 
			
		||||
		HistoryBlock *block = (*hist)[currentBlock];
 | 
			
		||||
		HistoryItem *item = (*block)[currentItem];
 | 
			
		||||
		HistoryBlock *block = hist->blocks[currentBlock];
 | 
			
		||||
		HistoryItem *item = block->items[currentItem];
 | 
			
		||||
 | 
			
		||||
		SelectedItems::const_iterator selEnd = _selected.cend();
 | 
			
		||||
		bool hasSel = !_selected.isEmpty();
 | 
			
		||||
| 
						 | 
				
			
			@ -153,15 +153,15 @@ void HistoryList::paintEvent(QPaintEvent *e) {
 | 
			
		|||
			item->draw(p, sel);
 | 
			
		||||
			p.translate(0, h);
 | 
			
		||||
			++iItem;
 | 
			
		||||
			if (iItem == block->size()) {
 | 
			
		||||
			if (iItem == block->items.size()) {
 | 
			
		||||
				iItem = 0;
 | 
			
		||||
				++iBlock;
 | 
			
		||||
				if (iBlock == hist->size()) {
 | 
			
		||||
				if (iBlock == hist->blocks.size()) {
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
				block = (*hist)[iBlock];
 | 
			
		||||
				block = hist->blocks[iBlock];
 | 
			
		||||
			}
 | 
			
		||||
			item = (*block)[iItem];
 | 
			
		||||
			item = block->items[iItem];
 | 
			
		||||
			y += h;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -685,7 +685,7 @@ void HistoryList::dragActionFinish(const QPoint &screenPos, Qt::MouseButton butt
 | 
			
		|||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			_selected.clear();
 | 
			
		||||
			parentWidget()->update();
 | 
			
		||||
			update();
 | 
			
		||||
		}
 | 
			
		||||
	} else if (_dragAction == Selecting) {
 | 
			
		||||
		if (_dragSelFrom && _dragSelTo) {
 | 
			
		||||
| 
						 | 
				
			
			@ -818,18 +818,18 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
 | 
			
		|||
				if (dynamic_cast<HistoryMessage*>(App::hoveredLinkItem()) && App::hoveredLinkItem()->id > 0) {
 | 
			
		||||
					_menu->addAction(lang(lng_context_forward_msg), historyWidget, SLOT(forwardMessage()))->setEnabled(true);
 | 
			
		||||
				}
 | 
			
		||||
				if ((!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) {
 | 
			
		||||
				if ((!hist->peer->isChannel() || hist->peer->asChannel()->adminned || App::hoveredLinkItem()->out())) {
 | 
			
		||||
					_menu->addAction(lang(lng_context_delete_msg), historyWidget, SLOT(deleteMessage()))->setEnabled(true);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (App::hoveredLinkItem()->id > 0 && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) {
 | 
			
		||||
			if (App::hoveredLinkItem()->id > 0 && !App::hoveredLinkItem()->serviceMsg() && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) {
 | 
			
		||||
				_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
 | 
			
		||||
			}
 | 
			
		||||
			App::contextItem(App::hoveredLinkItem());
 | 
			
		||||
		}
 | 
			
		||||
	} else { // maybe cursor on some text history item?
 | 
			
		||||
		bool canDelete = (item && item->itemType() == HistoryItem::MsgType) && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned);
 | 
			
		||||
		bool canForward = (item && item->itemType() == HistoryItem::MsgType) && (item->id > 0) && !item->serviceMsg();
 | 
			
		||||
		bool canDelete = (item && item->type() == HistoryItemMsg) && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned || item->out());
 | 
			
		||||
		bool canForward = (item && item->type() == HistoryItemMsg) && (item->id > 0) && !item->serviceMsg();
 | 
			
		||||
 | 
			
		||||
		HistoryMessage *msg = dynamic_cast<HistoryMessage*>(item);
 | 
			
		||||
		HistoryServiceMsg *srv = dynamic_cast<HistoryServiceMsg*>(item);
 | 
			
		||||
| 
						 | 
				
			
			@ -897,11 +897,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 && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) {
 | 
			
		||||
			if (item->id > 0 && !item->serviceMsg() && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) {
 | 
			
		||||
				_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if (App::mousedItem() && App::mousedItem()->itemType() == HistoryItem::MsgType && App::mousedItem()->id > 0 && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) {
 | 
			
		||||
			if (App::mousedItem() && !App::mousedItem()->serviceMsg() && App::mousedItem()->id > 0 && (!hist->peer->isChannel() || hist->peer->asChannel()->adminned)) {
 | 
			
		||||
				if (!_menu) _menu = new ContextMenu(this);
 | 
			
		||||
				_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
 | 
			
		||||
				item = App::mousedItem();
 | 
			
		||||
| 
						 | 
				
			
			@ -1006,7 +1006,7 @@ void HistoryList::saveContextFile() {
 | 
			
		|||
 | 
			
		||||
void HistoryList::copyContextText() {
 | 
			
		||||
	HistoryItem *item = App::contextItem();
 | 
			
		||||
	if (item && item->itemType() != HistoryItem::MsgType) {
 | 
			
		||||
	if (item && item->type() != HistoryItemMsg) {
 | 
			
		||||
		item = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1158,6 +1158,38 @@ void HistoryList::setFirstLoading(bool loading) {
 | 
			
		|||
	update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HistoryItem *HistoryList::atTopImportantMsg(int32 top, int32 height, int32 &bottomUnderScrollTop) const {
 | 
			
		||||
	if (hist->isEmpty()) return 0;
 | 
			
		||||
 | 
			
		||||
	adjustCurrent(top);
 | 
			
		||||
	for (int32 blockIndex = currentBlock + 1, itemIndex = currentItem + 1; blockIndex > 0;) {
 | 
			
		||||
		--blockIndex;
 | 
			
		||||
		HistoryBlock *block = hist->blocks[blockIndex];
 | 
			
		||||
		if (!itemIndex) itemIndex = block->items.size();
 | 
			
		||||
		for (; itemIndex > 0;) {
 | 
			
		||||
			--itemIndex;
 | 
			
		||||
			HistoryItem *item = block->items[itemIndex];
 | 
			
		||||
			if (item->isImportant()) {
 | 
			
		||||
				bottomUnderScrollTop = qMin(0, ySkip + item->y + item->block()->y + item->height() - top);
 | 
			
		||||
				return item;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		itemIndex = 0;
 | 
			
		||||
	}
 | 
			
		||||
	for (int32 blockIndex = currentBlock, itemIndex = currentItem + 1; blockIndex < hist->blocks.size(); ++blockIndex) {
 | 
			
		||||
		HistoryBlock *block = hist->blocks[blockIndex];
 | 
			
		||||
		for (; itemIndex < block->items.size(); ++itemIndex) {
 | 
			
		||||
			HistoryItem *item = block->items[itemIndex];
 | 
			
		||||
			if (item->isImportant()) {
 | 
			
		||||
				bottomUnderScrollTop = qMin(0, ySkip + item->y + item->block()->y + item->height() - top);
 | 
			
		||||
				return item;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		itemIndex = 0;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryList::updateSize() {
 | 
			
		||||
	int32 ph = scrollArea->height(), minadd = 0;
 | 
			
		||||
	int32 newYSkip = ph - (hist->height + st::historyPadding);
 | 
			
		||||
| 
						 | 
				
			
			@ -1211,30 +1243,30 @@ HistoryList::~HistoryList() {
 | 
			
		|||
	_dragAction = NoDrag;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryList::adjustCurrent(int32 y) {
 | 
			
		||||
void HistoryList::adjustCurrent(int32 y) const {
 | 
			
		||||
	if (hist->isEmpty()) return;
 | 
			
		||||
	if (currentBlock >= hist->size()) {
 | 
			
		||||
		currentBlock = hist->size() - 1;
 | 
			
		||||
	if (currentBlock >= hist->blocks.size()) {
 | 
			
		||||
		currentBlock = hist->blocks.size() - 1;
 | 
			
		||||
		currentItem = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while ((*hist)[currentBlock]->y + ySkip > y && currentBlock > 0) {
 | 
			
		||||
	while (hist->blocks[currentBlock]->y + ySkip > y && currentBlock > 0) {
 | 
			
		||||
		--currentBlock;
 | 
			
		||||
		currentItem = 0;
 | 
			
		||||
	}
 | 
			
		||||
	while ((*hist)[currentBlock]->y + (*hist)[currentBlock]->height + ySkip <= y && currentBlock + 1 < hist->size()) {
 | 
			
		||||
	while (hist->blocks[currentBlock]->y + hist->blocks[currentBlock]->height + ySkip <= y && currentBlock + 1 < hist->blocks.size()) {
 | 
			
		||||
		++currentBlock;
 | 
			
		||||
		currentItem = 0;
 | 
			
		||||
	}
 | 
			
		||||
	HistoryBlock *block = (*hist)[currentBlock];
 | 
			
		||||
	if (currentItem >= block->size()) {
 | 
			
		||||
		currentItem = block->size() - 1;
 | 
			
		||||
	HistoryBlock *block = hist->blocks[currentBlock];
 | 
			
		||||
	if (currentItem >= block->items.size()) {
 | 
			
		||||
		currentItem = block->items.size() - 1;
 | 
			
		||||
	}
 | 
			
		||||
	int32 by = block->y;
 | 
			
		||||
	while ((*block)[currentItem]->y + by + ySkip > y && currentItem > 0) {
 | 
			
		||||
	while (block->items[currentItem]->y + by + ySkip > y && currentItem > 0) {
 | 
			
		||||
		--currentItem;
 | 
			
		||||
	}
 | 
			
		||||
	while ((*block)[currentItem]->y + (*block)[currentItem]->height() + by + ySkip <= y && currentItem + 1 < block->size()) {
 | 
			
		||||
	while (block->items[currentItem]->y + block->items[currentItem]->height() + by + ySkip <= y && currentItem + 1 < block->items.size()) {
 | 
			
		||||
		++currentItem;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1242,13 +1274,13 @@ void HistoryList::adjustCurrent(int32 y) {
 | 
			
		|||
HistoryItem *HistoryList::prevItem(HistoryItem *item) {
 | 
			
		||||
	if (!item) return 0;
 | 
			
		||||
	HistoryBlock *block = item->block();
 | 
			
		||||
	int32 blockIndex = hist->indexOf(block), itemIndex = block->indexOf(item);
 | 
			
		||||
	int32 blockIndex = hist->blocks.indexOf(block), itemIndex = block->items.indexOf(item);
 | 
			
		||||
	if (blockIndex < 0  || itemIndex < 0) return 0;
 | 
			
		||||
	if (itemIndex > 0) {
 | 
			
		||||
		return (*block)[itemIndex - 1];
 | 
			
		||||
		return block->items[itemIndex - 1];
 | 
			
		||||
	}
 | 
			
		||||
	if (blockIndex > 0) {
 | 
			
		||||
		return *((*hist)[blockIndex - 1]->cend() - 1);
 | 
			
		||||
		return hist->blocks[blockIndex - 1]->items.back();
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1256,13 +1288,13 @@ HistoryItem *HistoryList::prevItem(HistoryItem *item) {
 | 
			
		|||
HistoryItem *HistoryList::nextItem(HistoryItem *item) {
 | 
			
		||||
	if (!item) return 0;
 | 
			
		||||
	HistoryBlock *block = item->block();
 | 
			
		||||
	int32 blockIndex = hist->indexOf(block), itemIndex = block->indexOf(item);
 | 
			
		||||
	int32 blockIndex = hist->blocks.indexOf(block), itemIndex = block->items.indexOf(item);
 | 
			
		||||
	if (blockIndex < 0  || itemIndex < 0) return 0;
 | 
			
		||||
	if (itemIndex + 1 < block->size()) {
 | 
			
		||||
		return (*block)[itemIndex + 1];
 | 
			
		||||
	if (itemIndex + 1 < block->items.size()) {
 | 
			
		||||
		return block->items[itemIndex + 1];
 | 
			
		||||
	}
 | 
			
		||||
	if (blockIndex + 1 < hist->size()) {
 | 
			
		||||
		return *(*hist)[blockIndex + 1]->cbegin();
 | 
			
		||||
	if (blockIndex + 1 < hist->blocks.size()) {
 | 
			
		||||
		return hist->blocks[blockIndex + 1]->items.front();
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1278,7 +1310,7 @@ bool HistoryList::canDeleteSelected() const {
 | 
			
		|||
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()->itemType() == HistoryItem::MsgType && i.value() == FullItemSel) {
 | 
			
		||||
		if (i.key()->type() == HistoryItemMsg && i.value() == FullItemSel) {
 | 
			
		||||
			++selectedForDelete;
 | 
			
		||||
			if (!i.key()->serviceMsg() && i.key()->id > 0) {
 | 
			
		||||
				++selectedForForward;
 | 
			
		||||
| 
						 | 
				
			
			@ -1337,8 +1369,8 @@ void HistoryList::onUpdateSelected() {
 | 
			
		|||
	if (!hist->isEmpty()) {
 | 
			
		||||
		adjustCurrent(point.y());
 | 
			
		||||
 | 
			
		||||
		block = (*hist)[currentBlock];
 | 
			
		||||
		item = (*block)[currentItem];
 | 
			
		||||
		block = hist->blocks[currentBlock];
 | 
			
		||||
		item = block->items[currentItem];
 | 
			
		||||
 | 
			
		||||
		App::mousedItem(item);
 | 
			
		||||
		m = mapMouseToItem(point, item);
 | 
			
		||||
| 
						 | 
				
			
			@ -1505,7 +1537,7 @@ void HistoryList::updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dra
 | 
			
		|||
	}
 | 
			
		||||
	if (!force) return;
 | 
			
		||||
	
 | 
			
		||||
	parentWidget()->update();
 | 
			
		||||
	update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryList::applyDragSelection() {
 | 
			
		||||
| 
						 | 
				
			
			@ -1519,13 +1551,13 @@ void HistoryList::applyDragSelection(SelectedItems *toItems) const {
 | 
			
		|||
 | 
			
		||||
	int32 fromy = _dragSelFrom->y + _dragSelFrom->block()->y, toy = _dragSelTo->y + _dragSelTo->block()->y + _dragSelTo->height();
 | 
			
		||||
	if (_dragSelecting) {
 | 
			
		||||
		int32 fromblock = hist->indexOf(_dragSelFrom->block()), fromitem = _dragSelFrom->block()->indexOf(_dragSelFrom);
 | 
			
		||||
		int32 toblock = hist->indexOf(_dragSelTo->block()), toitem = _dragSelTo->block()->indexOf(_dragSelTo);
 | 
			
		||||
		int32 fromblock = hist->blocks.indexOf(_dragSelFrom->block()), fromitem = _dragSelFrom->block()->items.indexOf(_dragSelFrom);
 | 
			
		||||
		int32 toblock = hist->blocks.indexOf(_dragSelTo->block()), toitem = _dragSelTo->block()->items.indexOf(_dragSelTo);
 | 
			
		||||
		if (fromblock >= 0 && fromitem >= 0 && toblock >= 0 && toitem >= 0) {
 | 
			
		||||
			for (; fromblock <= toblock; ++fromblock) {
 | 
			
		||||
				HistoryBlock *block = (*hist)[fromblock];
 | 
			
		||||
				for (int32 cnt = (fromblock < toblock) ? block->size() : (toitem + 1); fromitem < cnt; ++fromitem) {
 | 
			
		||||
					HistoryItem *item = (*block)[fromitem];
 | 
			
		||||
				HistoryBlock *block = hist->blocks[fromblock];
 | 
			
		||||
				for (int32 cnt = (fromblock < toblock) ? block->items.size() : (toitem + 1); fromitem < cnt; ++fromitem) {
 | 
			
		||||
					HistoryItem *item = block->items[fromitem];
 | 
			
		||||
					SelectedItems::iterator i = toItems->find(item);
 | 
			
		||||
					if (item->id > 0 && !item->serviceMsg()) {
 | 
			
		||||
						if (i == toItems->cend()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2066,7 +2098,7 @@ bool HistoryHider::withConfirm() const {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void HistoryHider::paintEvent(QPaintEvent *e) {
 | 
			
		||||
	QPainter p(this);
 | 
			
		||||
	Painter p(this);
 | 
			
		||||
	if (!hiding || !cacheForAnim.isNull() || !offered) {
 | 
			
		||||
		p.setOpacity(aOpacity.current() * st::layerAlpha);
 | 
			
		||||
		p.fillRect(0, st::titleShadow, width(), height() - st::titleShadow, st::layerBG->b);
 | 
			
		||||
| 
						 | 
				
			
			@ -2234,6 +2266,15 @@ HistoryHider::~HistoryHider() {
 | 
			
		|||
	parent()->noHider(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CollapseButton::CollapseButton(QWidget *parent) : FlatButton(parent, lang(lng_channel_hide_comments), st::collapseButton) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CollapseButton::paintEvent(QPaintEvent *e) {
 | 
			
		||||
	Painter p(this);
 | 
			
		||||
	App::roundRect(p, rect(), App::msgServiceBg(), ServiceCorners);
 | 
			
		||||
	FlatButton::paintEvent(e);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
 | 
			
		||||
, _replyToId(0)
 | 
			
		||||
, _replyTo(0)
 | 
			
		||||
| 
						 | 
				
			
			@ -2250,6 +2291,8 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
 | 
			
		|||
, _channel(NoChannel)
 | 
			
		||||
, _clearPeer(0)
 | 
			
		||||
, _showAtMsgId(0)
 | 
			
		||||
, _fixedInScrollMsgId(0)
 | 
			
		||||
, _fixedInScrollMsgTop(0)
 | 
			
		||||
, _preloadRequest(0), _preloadDownRequest(0)
 | 
			
		||||
, _delayedShowAtMsgId(-1)
 | 
			
		||||
, _delayedShowAtRequest(0)
 | 
			
		||||
| 
						 | 
				
			
			@ -2259,6 +2302,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
 | 
			
		|||
, _history(0)
 | 
			
		||||
, _histInited(false)
 | 
			
		||||
, _toHistoryEnd(this, st::historyToEnd)
 | 
			
		||||
, _collapseComments(this)
 | 
			
		||||
, _attachMention(this)
 | 
			
		||||
, _reportSpamPanel(this)
 | 
			
		||||
, _send(this, lang(lng_send_button), st::btnSend)
 | 
			
		||||
| 
						 | 
				
			
			@ -2309,6 +2353,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
 | 
			
		|||
	connect(&_reportSpamPanel, SIGNAL(hideClicked()), this, SLOT(onReportSpamHide()));
 | 
			
		||||
	connect(&_reportSpamPanel, SIGNAL(clearClicked()), this, SLOT(onReportSpamClear()));
 | 
			
		||||
	connect(&_toHistoryEnd, SIGNAL(clicked()), this, SLOT(onHistoryToEnd()));
 | 
			
		||||
	connect(&_collapseComments, SIGNAL(clicked()), this, SLOT(onCollapseComments()));
 | 
			
		||||
	connect(&_replyForwardPreviewCancel, SIGNAL(clicked()), this, SLOT(onReplyForwardPreviewCancel()));
 | 
			
		||||
	connect(&_send, SIGNAL(clicked()), this, SLOT(onSend()));
 | 
			
		||||
	connect(&_unblock, SIGNAL(clicked()), this, SLOT(onUnblock()));
 | 
			
		||||
| 
						 | 
				
			
			@ -2354,6 +2399,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
 | 
			
		|||
 | 
			
		||||
	_scroll.hide();
 | 
			
		||||
	_scroll.move(0, 0);
 | 
			
		||||
	_collapseComments.setParent(&_scroll);
 | 
			
		||||
 | 
			
		||||
	_kbScroll.setFocusPolicy(Qt::NoFocus);
 | 
			
		||||
	_kbScroll.viewport()->setFocusPolicy(Qt::NoFocus);
 | 
			
		||||
| 
						 | 
				
			
			@ -2367,6 +2413,9 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
 | 
			
		|||
	_toHistoryEnd.hide();
 | 
			
		||||
	_toHistoryEnd.installEventFilter(this);
 | 
			
		||||
 | 
			
		||||
	_collapseComments.hide();
 | 
			
		||||
	_collapseComments.installEventFilter(this);
 | 
			
		||||
 | 
			
		||||
	_attachMention.hide();
 | 
			
		||||
	connect(&_attachMention, SIGNAL(chosen(QString)), this, SLOT(onMentionHashtagOrBotCommandInsert(QString)));
 | 
			
		||||
	_field.installEventFilter(&_attachMention);
 | 
			
		||||
| 
						 | 
				
			
			@ -2759,7 +2808,7 @@ void HistoryWidget::setKbWasHidden() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::fastShowAtEnd(History *h) {
 | 
			
		||||
	h->getReadyFor(ShowAtTheEndMsgId);
 | 
			
		||||
	h->getReadyFor(ShowAtTheEndMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
 | 
			
		||||
 | 
			
		||||
	if (_history != h) return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2768,7 +2817,7 @@ void HistoryWidget::fastShowAtEnd(History *h) {
 | 
			
		|||
	_showAtMsgId = ShowAtTheEndMsgId;
 | 
			
		||||
	_histInited = false;
 | 
			
		||||
 | 
			
		||||
	if (h->isReadyFor(_showAtMsgId)) {
 | 
			
		||||
	if (h->isReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop)) {
 | 
			
		||||
		historyLoaded();
 | 
			
		||||
	} else {
 | 
			
		||||
		firstLoadMessages();
 | 
			
		||||
| 
						 | 
				
			
			@ -2781,10 +2830,19 @@ void HistoryWidget::showPeerHistory(const PeerId &peerId, MsgId showAtMsgId) {
 | 
			
		|||
		if (_peer->id == peerId) {
 | 
			
		||||
			_history->lastWidth = 0;
 | 
			
		||||
 | 
			
		||||
			bool canShowNow = _history->isReadyFor(showAtMsgId, true);
 | 
			
		||||
			bool wasOnlyImportant = _history->isChannel() ? _history->asChannelHistory()->onlyImportant() : true;
 | 
			
		||||
 | 
			
		||||
			bool canShowNow = _history->isReadyFor(showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
 | 
			
		||||
			if (_fixedInScrollMsgId) {
 | 
			
		||||
				_fixedInScrollMsgTop += _list->height() - _scroll.scrollTop() - st::historyPadding;
 | 
			
		||||
			}
 | 
			
		||||
			if (!canShowNow) {
 | 
			
		||||
				delayedShowAt(showAtMsgId);
 | 
			
		||||
			} else {
 | 
			
		||||
				if (_history->isChannel() && wasOnlyImportant != _history->asChannelHistory()->onlyImportant()) {
 | 
			
		||||
					clearAllLoadRequests();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				clearDelayedShowAt();
 | 
			
		||||
				if (_replyReturn && _replyReturn->id == showAtMsgId) {
 | 
			
		||||
					calcNextReplyReturn();
 | 
			
		||||
| 
						 | 
				
			
			@ -2896,7 +2954,9 @@ void HistoryWidget::showPeerHistory(const PeerId &peerId, MsgId showAtMsgId) {
 | 
			
		|||
		_scroll.setWidget(_list);
 | 
			
		||||
		_list->show();
 | 
			
		||||
 | 
			
		||||
		if (_history->lastWidth || _history->isReadyFor(_showAtMsgId, true)) {
 | 
			
		||||
		if (_history->lastWidth || _history->isReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop)) {
 | 
			
		||||
			_fixedInScrollMsgId = 0;
 | 
			
		||||
			_fixedInScrollMsgTop = 0;
 | 
			
		||||
			historyLoaded();
 | 
			
		||||
		} else {
 | 
			
		||||
			firstLoadMessages();
 | 
			
		||||
| 
						 | 
				
			
			@ -2993,17 +3053,17 @@ void HistoryWidget::updateReportSpamStatus() {
 | 
			
		|||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if ((!_history->loadedAtTop() && (_history->size() < 2 || (_history->size() == 2 && _history->at(1)->size() < 2))) || !cContactsReceived() || _firstLoadRequest) {
 | 
			
		||||
	if ((!_history->loadedAtTop() && (_history->blocks.size() < 2 || (_history->blocks.size() == 2 && _history->blocks.at(1)->items.size() < 2))) || !cContactsReceived() || _firstLoadRequest) {
 | 
			
		||||
		_reportSpamStatus = dbiprsUnknown;
 | 
			
		||||
	} else if (_peer->isUser()) {
 | 
			
		||||
		if (_peer->asUser()->contact > 0) {
 | 
			
		||||
			_reportSpamStatus = dbiprsNoButton;
 | 
			
		||||
		} else {
 | 
			
		||||
			bool anyFound = false, outFound = false;
 | 
			
		||||
			for (int32 i = 0, l = _history->size(); i < l; ++i) {
 | 
			
		||||
				for (int32 j = 0, c = _history->at(i)->size(); j < c; ++j) {
 | 
			
		||||
			for (int32 i = 0, l = _history->blocks.size(); i < l; ++i) {
 | 
			
		||||
				for (int32 j = 0, c = _history->blocks.at(i)->items.size(); j < c; ++j) {
 | 
			
		||||
					anyFound = true;
 | 
			
		||||
					if (_history->at(i)->at(j)->out()) {
 | 
			
		||||
					if (_history->blocks.at(i)->items.at(j)->out()) {
 | 
			
		||||
						outFound = true;
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
| 
						 | 
				
			
			@ -3055,6 +3115,7 @@ void HistoryWidget::updateControlsVisibility() {
 | 
			
		|||
		_attachPhoto.hide();
 | 
			
		||||
		_attachEmoji.hide();
 | 
			
		||||
		_toHistoryEnd.hide();
 | 
			
		||||
		_collapseComments.hide();
 | 
			
		||||
		_kbShow.hide();
 | 
			
		||||
		_kbHide.hide();
 | 
			
		||||
		_cmdStart.hide();
 | 
			
		||||
| 
						 | 
				
			
			@ -3233,7 +3294,7 @@ void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::historyToDown(History *history) {
 | 
			
		||||
	history->lastScrollTop = History::ScrollMax;
 | 
			
		||||
	history->lastScrollTop = ScrollMax;
 | 
			
		||||
	if (history == _history) {
 | 
			
		||||
		_scroll.scrollToY(_scroll.scrollTopMax());
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -3274,38 +3335,39 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
 | 
			
		|||
 | 
			
		||||
	int32 count = 0;
 | 
			
		||||
	const QVector<MTPMessage> emptyList, *histList = &emptyList;
 | 
			
		||||
	const QVector<MTPMessageGroup> *histCollapsed = 0;
 | 
			
		||||
	switch (messages.type()) {
 | 
			
		||||
	case mtpc_messages_messages: {
 | 
			
		||||
		const MTPDmessages_messages &data(messages.c_messages_messages());
 | 
			
		||||
		App::feedUsers(data.vusers);
 | 
			
		||||
		App::feedChats(data.vchats);
 | 
			
		||||
		histList = &data.vmessages.c_vector().v;
 | 
			
		||||
		const MTPDmessages_messages &d(messages.c_messages_messages());
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
		App::feedChats(d.vchats);
 | 
			
		||||
		histList = &d.vmessages.c_vector().v;
 | 
			
		||||
		count = histList->size();
 | 
			
		||||
	} break;
 | 
			
		||||
	case mtpc_messages_messagesSlice: {
 | 
			
		||||
		const MTPDmessages_messagesSlice &data(messages.c_messages_messagesSlice());
 | 
			
		||||
		App::feedUsers(data.vusers);
 | 
			
		||||
		App::feedChats(data.vchats);
 | 
			
		||||
		histList = &data.vmessages.c_vector().v;
 | 
			
		||||
		count = data.vcount.v;
 | 
			
		||||
		const MTPDmessages_messagesSlice &d(messages.c_messages_messagesSlice());
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
		App::feedChats(d.vchats);
 | 
			
		||||
		histList = &d.vmessages.c_vector().v;
 | 
			
		||||
		count = d.vcount.v;
 | 
			
		||||
	} break;
 | 
			
		||||
	case mtpc_messages_channelMessages: {
 | 
			
		||||
		const MTPDmessages_channelMessages &data(messages.c_messages_channelMessages());
 | 
			
		||||
		const MTPDmessages_channelMessages &d(messages.c_messages_channelMessages());
 | 
			
		||||
		if (peer && peer->isChannel()) {
 | 
			
		||||
			peer->asChannel()->ptsReceived(data.vpts.v);
 | 
			
		||||
			peer->asChannel()->ptsReceived(d.vpts.v);
 | 
			
		||||
		} else {
 | 
			
		||||
			LOG(("App Error: received messages.channelMessages in HistoryWidget::messagesReceived when no channel was passed!"));
 | 
			
		||||
			LOG(("API Error: received messages.channelMessages when no channel was passed! (HistoryWidget::messagesReceived)"));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		App::feedUsers(data.vusers);
 | 
			
		||||
		App::feedChats(data.vchats);
 | 
			
		||||
		histList = &data.vmessages.c_vector().v;
 | 
			
		||||
		count = data.vcount.v;
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
		App::feedChats(d.vchats);
 | 
			
		||||
		histList = &d.vmessages.c_vector().v;
 | 
			
		||||
		if (d.has_collapsed()) histCollapsed = &d.vcollapsed.c_vector().v;
 | 
			
		||||
		count = d.vcount.v;
 | 
			
		||||
	} break;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	if (_preloadRequest == requestId) {
 | 
			
		||||
		addMessagesToFront(*histList);
 | 
			
		||||
		addMessagesToFront(*histList, histCollapsed);
 | 
			
		||||
		_preloadRequest = 0;
 | 
			
		||||
		onListScroll();
 | 
			
		||||
		if (_reportSpamStatus == dbiprsUnknown) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3313,12 +3375,15 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
 | 
			
		|||
			if (_reportSpamStatus != dbiprsUnknown) updateControlsVisibility();
 | 
			
		||||
		}
 | 
			
		||||
	} else if (_preloadDownRequest == requestId) {
 | 
			
		||||
		addMessagesToBack(*histList);
 | 
			
		||||
		addMessagesToBack(*histList, histCollapsed);
 | 
			
		||||
		_preloadDownRequest = 0;
 | 
			
		||||
		onListScroll();
 | 
			
		||||
		if (_history->loadedAtBottom() && App::wnd()) App::wnd()->checkHistoryActivation();
 | 
			
		||||
	} else if (_firstLoadRequest == requestId) {
 | 
			
		||||
		addMessagesToFront(*histList);
 | 
			
		||||
		addMessagesToFront(*histList, histCollapsed);
 | 
			
		||||
		if (_fixedInScrollMsgId && _history->isChannel()) {
 | 
			
		||||
			_history->asChannelHistory()->insertCollapseItem(_fixedInScrollMsgId);
 | 
			
		||||
		}
 | 
			
		||||
		_firstLoadRequest = 0;
 | 
			
		||||
		if (_history->loadedAtTop()) {
 | 
			
		||||
			if (_history->unreadCount > count) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3333,14 +3398,21 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
 | 
			
		|||
		historyLoaded();
 | 
			
		||||
	} else if (_delayedShowAtRequest == requestId) {
 | 
			
		||||
		_delayedShowAtRequest = 0;
 | 
			
		||||
		_history->getReadyFor(_delayedShowAtMsgId);
 | 
			
		||||
		bool wasOnlyImportant = _history->isChannel() ? _history->asChannelHistory()->onlyImportant() : true;
 | 
			
		||||
		_history->getReadyFor(_delayedShowAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
 | 
			
		||||
		if (_fixedInScrollMsgId) {
 | 
			
		||||
			_fixedInScrollMsgTop += _list->height() - _scroll.scrollTop() - st::historyPadding;
 | 
			
		||||
		}
 | 
			
		||||
		if (_history->isEmpty()) {
 | 
			
		||||
			if (_preloadRequest) MTP::cancel(_preloadRequest);
 | 
			
		||||
			if (_preloadDownRequest) MTP::cancel(_preloadDownRequest);
 | 
			
		||||
			if (_firstLoadRequest) MTP::cancel(_firstLoadRequest);
 | 
			
		||||
			_preloadRequest = _preloadDownRequest = 0;
 | 
			
		||||
			_firstLoadRequest = -1; // hack - don't updateListSize yet
 | 
			
		||||
			addMessagesToFront(*histList);
 | 
			
		||||
			addMessagesToFront(*histList, histCollapsed);
 | 
			
		||||
			if (_fixedInScrollMsgId && _history->isChannel()) {
 | 
			
		||||
				_history->asChannelHistory()->insertCollapseItem(_fixedInScrollMsgId);
 | 
			
		||||
			}
 | 
			
		||||
			_firstLoadRequest = 0;
 | 
			
		||||
			if (_history->loadedAtTop()) {
 | 
			
		||||
				if (_history->unreadCount > count) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3359,6 +3431,10 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
 | 
			
		|||
		_showAtMsgId = _delayedShowAtMsgId;
 | 
			
		||||
		_histInited = false;
 | 
			
		||||
 | 
			
		||||
		if (_history->isChannel() && wasOnlyImportant != _history->asChannelHistory()->onlyImportant()) {
 | 
			
		||||
			clearAllLoadRequests();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		historyLoaded();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -3386,24 +3462,49 @@ bool HistoryWidget::isActive() const {
 | 
			
		|||
void HistoryWidget::firstLoadMessages() {
 | 
			
		||||
	if (!_history || _firstLoadRequest) return;
 | 
			
		||||
 | 
			
		||||
	bool loadImportant = _history->isChannel() ? _history->asChannelHistory()->onlyImportant() : false, wasOnlyImportant = loadImportant;
 | 
			
		||||
	int32 from = 0, offset = 0, loadCount = MessagesPerPage;
 | 
			
		||||
	if (_showAtMsgId == ShowAtUnreadMsgId) {
 | 
			
		||||
		if (_history->unreadCount) {
 | 
			
		||||
			_history->getReadyFor(_showAtMsgId);
 | 
			
		||||
			_history->getReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
 | 
			
		||||
			offset = -loadCount / 2;
 | 
			
		||||
			from = _history->inboxReadBefore;
 | 
			
		||||
		} else {
 | 
			
		||||
			_history->getReadyFor(ShowAtTheEndMsgId);
 | 
			
		||||
			_history->getReadyFor(ShowAtTheEndMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (_showAtMsgId == ShowAtTheEndMsgId) {
 | 
			
		||||
		_history->getReadyFor(_showAtMsgId);
 | 
			
		||||
		_history->getReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
 | 
			
		||||
		loadCount = MessagesFirstLoad;
 | 
			
		||||
	} else if (_showAtMsgId > 0) {
 | 
			
		||||
		_history->getReadyFor(_showAtMsgId);
 | 
			
		||||
		_history->getReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
 | 
			
		||||
		offset = -loadCount / 2;
 | 
			
		||||
		from = _showAtMsgId;
 | 
			
		||||
	} else if (_showAtMsgId < 0 && _history->isChannel()) {
 | 
			
		||||
		if (_showAtMsgId == SwitchAtTopMsgId) {
 | 
			
		||||
			_history->getReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
 | 
			
		||||
			loadImportant = true;
 | 
			
		||||
		} else if (HistoryItem *item = App::histItemById(_channel, _delayedShowAtMsgId)) {
 | 
			
		||||
			if (item->type() == HistoryItemGroup) {
 | 
			
		||||
				_history->getReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
 | 
			
		||||
				offset = -loadCount / 2;
 | 
			
		||||
				from = qMax(static_cast<HistoryGroup*>(item)->minId(), 1);
 | 
			
		||||
				loadImportant = false;
 | 
			
		||||
			} else if (item->type() == HistoryItemCollapse) {
 | 
			
		||||
				_history->getReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
 | 
			
		||||
				offset = -loadCount / 2;
 | 
			
		||||
				from = qMax(static_cast<HistoryCollapse*>(item)->wasMinId(), 1);
 | 
			
		||||
				loadImportant = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (_fixedInScrollMsgId) {
 | 
			
		||||
			_fixedInScrollMsgTop += _list->height() - _scroll.scrollTop() - st::historyPadding;
 | 
			
		||||
		}
 | 
			
		||||
		if (_history->isEmpty() || wasOnlyImportant != loadImportant) {
 | 
			
		||||
			clearAllLoadRequests();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (_peer->isChannel()) {
 | 
			
		||||
 | 
			
		||||
	if (loadImportant) {
 | 
			
		||||
		_firstLoadRequest = MTP::send(MTPchannels_GetImportantHistory(_peer->asChannel()->inputChannel, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed));
 | 
			
		||||
	} else {
 | 
			
		||||
		_firstLoadRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed));
 | 
			
		||||
| 
						 | 
				
			
			@ -3413,9 +3514,11 @@ void HistoryWidget::firstLoadMessages() {
 | 
			
		|||
void HistoryWidget::loadMessages() {
 | 
			
		||||
	if (!_history || _history->loadedAtTop() || _preloadRequest) return;
 | 
			
		||||
 | 
			
		||||
	bool loadImportant = _history->isChannel() ? _history->asChannelHistory()->onlyImportant() : false;
 | 
			
		||||
	MsgId min = _history->minMsgId();
 | 
			
		||||
	int32 offset = 0, loadCount = min ? MessagesPerPage : MessagesFirstLoad;
 | 
			
		||||
	if (_peer->isChannel()) {
 | 
			
		||||
 | 
			
		||||
	if (loadImportant) {
 | 
			
		||||
		_preloadRequest = MTP::send(MTPchannels_GetImportantHistory(_peer->asChannel()->inputChannel, MTP_int(min), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed));
 | 
			
		||||
	} else {
 | 
			
		||||
		_preloadRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(min), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed));
 | 
			
		||||
| 
						 | 
				
			
			@ -3428,8 +3531,10 @@ void HistoryWidget::loadMessagesDown() {
 | 
			
		|||
	MsgId max = _history->maxMsgId();
 | 
			
		||||
	if (!max) return;
 | 
			
		||||
 | 
			
		||||
	bool loadImportant = _history->isChannel() ? _history->asChannelHistory()->onlyImportant() : false;
 | 
			
		||||
	int32 loadCount = MessagesPerPage, offset = -loadCount;
 | 
			
		||||
	if (_peer->isChannel()) {
 | 
			
		||||
 | 
			
		||||
	if (loadImportant) {
 | 
			
		||||
		_preloadDownRequest = MTP::send(MTPchannels_GetImportantHistory(_peer->asChannel()->inputChannel, MTP_int(max + 1), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed));
 | 
			
		||||
	} else {
 | 
			
		||||
		_preloadDownRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(max + 1), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed));
 | 
			
		||||
| 
						 | 
				
			
			@ -3442,22 +3547,37 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) {
 | 
			
		|||
	clearDelayedShowAt();
 | 
			
		||||
	_delayedShowAtMsgId = showAtMsgId;
 | 
			
		||||
 | 
			
		||||
	int32 from = _delayedShowAtMsgId, offset = 0, loadCount = MessagesPerPage;
 | 
			
		||||
	bool loadImportant = _history->isChannel() ? _history->asChannelHistory()->onlyImportant() : false;
 | 
			
		||||
	int32 from = 0, offset = 0, loadCount = MessagesPerPage;
 | 
			
		||||
	if (_delayedShowAtMsgId == ShowAtUnreadMsgId) {
 | 
			
		||||
		if (_history->unreadCount) {
 | 
			
		||||
			offset = -loadCount / 2;
 | 
			
		||||
			from = _history->inboxReadBefore;
 | 
			
		||||
		} else {
 | 
			
		||||
			loadCount = MessagesFirstLoad;
 | 
			
		||||
			from = 0;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (_delayedShowAtMsgId == ShowAtTheEndMsgId) {
 | 
			
		||||
		loadCount = MessagesFirstLoad;
 | 
			
		||||
		from = 0;
 | 
			
		||||
	} else if (_delayedShowAtMsgId > 0) {
 | 
			
		||||
		offset = -loadCount / 2;
 | 
			
		||||
		from = _delayedShowAtMsgId;
 | 
			
		||||
	} else if (_delayedShowAtMsgId < 0 && _history->isChannel()) {
 | 
			
		||||
		if (_delayedShowAtMsgId == SwitchAtTopMsgId) {
 | 
			
		||||
			loadImportant = true;
 | 
			
		||||
		} else if (HistoryItem *item = App::histItemById(_channel, _delayedShowAtMsgId)) {
 | 
			
		||||
			if (item->type() == HistoryItemGroup) {
 | 
			
		||||
				offset = -loadCount / 2;
 | 
			
		||||
				from = qMax(static_cast<HistoryGroup*>(item)->minId(), 1);
 | 
			
		||||
				loadImportant = false;
 | 
			
		||||
			} else if (item->type() == HistoryItemCollapse) {
 | 
			
		||||
				offset = -loadCount / 2;
 | 
			
		||||
				from = qMax(static_cast<HistoryCollapse*>(item)->wasMinId(), 1);
 | 
			
		||||
				loadImportant = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (_peer->isChannel()) {
 | 
			
		||||
 | 
			
		||||
	if (loadImportant) {
 | 
			
		||||
		_delayedShowAtRequest = MTP::send(MTPchannels_GetImportantHistory(_peer->asChannel()->inputChannel, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed));
 | 
			
		||||
	} else {
 | 
			
		||||
		_delayedShowAtRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed));
 | 
			
		||||
| 
						 | 
				
			
			@ -3469,6 +3589,7 @@ void HistoryWidget::onListScroll() {
 | 
			
		|||
	if (_firstLoadRequest || _scroll.isHidden()) return;
 | 
			
		||||
 | 
			
		||||
	updateToEndVisibility();
 | 
			
		||||
	updateCollapseCommentsVisibility();
 | 
			
		||||
	
 | 
			
		||||
	int st = _scroll.scrollTop(), stm = _scroll.scrollTopMax(), sh = _scroll.height();
 | 
			
		||||
	if (st + PreloadHeightsCount * sh > stm) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3480,7 +3601,7 @@ void HistoryWidget::onListScroll() {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	while (_replyReturn) {
 | 
			
		||||
		bool below = (_replyReturn->detached() && !_history->isEmpty() && _replyReturn->id < _history->back()->back()->id);
 | 
			
		||||
		bool below = (_replyReturn->detached() && !_history->isEmpty() && _replyReturn->id < _history->blocks.back()->items.back()->id);
 | 
			
		||||
		if (!below && !_replyReturn->detached()) below = (st >= stm) || (_replyReturn->y + _replyReturn->block()->y < st + sh / 2);
 | 
			
		||||
		if (below) {
 | 
			
		||||
			calcNextReplyReturn();
 | 
			
		||||
| 
						 | 
				
			
			@ -3513,6 +3634,10 @@ void HistoryWidget::onHistoryToEnd() {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::onCollapseComments() {
 | 
			
		||||
	showPeerHistory(_peer->id, SwitchAtTopMsgId);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
 | 
			
		||||
	if (!_history) return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3638,7 +3763,7 @@ void HistoryWidget::shareContact(const PeerId &peer, const QString &phone, const
 | 
			
		|||
	} else {
 | 
			
		||||
		flags |= MTPDmessage::flag_from_id;
 | 
			
		||||
	}
 | 
			
		||||
	h->addToBack(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)));
 | 
			
		||||
	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);
 | 
			
		||||
| 
						 | 
				
			
			@ -3662,6 +3787,14 @@ MsgId HistoryWidget::msgId() const {
 | 
			
		|||
	return _showAtMsgId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HistoryItem *HistoryWidget::atTopImportantMsg(int32 &bottomUnderScrollTop) const {
 | 
			
		||||
	if (!_list || !_history->isChannel()) {
 | 
			
		||||
		bottomUnderScrollTop = 0;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return _list->atTopImportantMsg(_scroll.scrollTop(), _scroll.height(), bottomUnderScrollTop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back) {
 | 
			
		||||
	_bgAnimCache = bgAnimCache;
 | 
			
		||||
	_bgAnimTopBarCache = bgAnimTopBarCache;
 | 
			
		||||
| 
						 | 
				
			
			@ -3673,6 +3806,7 @@ void HistoryWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTo
 | 
			
		|||
	_kbScroll.hide();
 | 
			
		||||
	_reportSpamPanel.hide();
 | 
			
		||||
	_toHistoryEnd.hide();
 | 
			
		||||
	_collapseComments.hide();
 | 
			
		||||
	_attachDocument.hide();
 | 
			
		||||
	_attachPhoto.hide();
 | 
			
		||||
	_attachEmoji.hide();
 | 
			
		||||
| 
						 | 
				
			
			@ -3978,7 +4112,7 @@ void HistoryWidget::insertBotCommand(const QString &cmd) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
bool HistoryWidget::eventFilter(QObject *obj, QEvent *e) {
 | 
			
		||||
	if (obj == &_toHistoryEnd && e->type() == QEvent::Wheel) {
 | 
			
		||||
	if ((obj == &_toHistoryEnd || obj == &_collapseComments) && e->type() == QEvent::Wheel) {
 | 
			
		||||
		return _scroll.viewportEvent(e);
 | 
			
		||||
	}
 | 
			
		||||
	return TWidget::eventFilter(obj, e);
 | 
			
		||||
| 
						 | 
				
			
			@ -4062,7 +4196,7 @@ bool HistoryWidget::canSendMessages(PeerData *peer) {
 | 
			
		|||
		} else if (peer->isChat()) {
 | 
			
		||||
			return !peer->asChat()->forbidden && !peer->asChat()->left;
 | 
			
		||||
		} else if (peer->isChannel()) {
 | 
			
		||||
			return !peer->asChannel()->forbidden && !peer->asChannel()->left && peer->asChannel()->adminned;
 | 
			
		||||
			return !peer->asChannel()->forbidden && !peer->asChannel()->left && (peer->asChannel()->adminned || !peer->asChannel()->isBroadcast);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -4219,7 +4353,7 @@ void HistoryWidget::contextMenuEvent(QContextMenuEvent *e) {
 | 
			
		|||
 | 
			
		||||
void HistoryWidget::deleteMessage() {
 | 
			
		||||
	HistoryItem *item = App::contextItem();
 | 
			
		||||
	if (!item || item->itemType() != HistoryItem::MsgType) return;
 | 
			
		||||
	if (!item || item->type() != HistoryItemMsg) return;
 | 
			
		||||
 | 
			
		||||
	HistoryMessage *msg = dynamic_cast<HistoryMessage*>(item);
 | 
			
		||||
	App::main()->deleteLayer((msg && msg->uploading()) ? -2 : -1);
 | 
			
		||||
| 
						 | 
				
			
			@ -4227,14 +4361,14 @@ void HistoryWidget::deleteMessage() {
 | 
			
		|||
 | 
			
		||||
void HistoryWidget::forwardMessage() {
 | 
			
		||||
	HistoryItem *item = App::contextItem();
 | 
			
		||||
	if (!item || item->itemType() != HistoryItem::MsgType) return;
 | 
			
		||||
	if (!item || item->type() != HistoryItemMsg || item->serviceMsg()) return;
 | 
			
		||||
 | 
			
		||||
	App::main()->forwardLayer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::selectMessage() {
 | 
			
		||||
	HistoryItem *item = App::contextItem();
 | 
			
		||||
	if (!item || item->itemType() != HistoryItem::MsgType) return;
 | 
			
		||||
	if (!item || item->type() != HistoryItemMsg || item->serviceMsg()) return;
 | 
			
		||||
 | 
			
		||||
	if (_list) _list->selectItem(item);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4547,12 +4681,12 @@ void HistoryWidget::confirmSendImage(const ReadyLocalMedia &img) {
 | 
			
		|||
		flags |= MTPDmessage::flag_from_id;
 | 
			
		||||
	}
 | 
			
		||||
	if (img.type == ToPreparePhoto) {
 | 
			
		||||
		h->addToBack(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)));
 | 
			
		||||
	} else if (img.type == ToPrepareDocument) {
 | 
			
		||||
		h->addToBack(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)));
 | 
			
		||||
	} else if (img.type == ToPrepareAudio) {
 | 
			
		||||
		flags |= MTPDmessage_flag_media_unread;
 | 
			
		||||
		h->addToBack(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)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (_peer && img.peer == _peer->id) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4857,6 +4991,7 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
 | 
			
		|||
	_field.resize(width() - _send.width() - _attachDocument.width() - _attachEmoji.width() - (kbShowShown ? _kbShow.width() : 0) - (_cmdStartShown ? _cmdStart.width() : 0), _field.height());
 | 
			
		||||
 | 
			
		||||
	_toHistoryEnd.move((width() - _toHistoryEnd.width()) / 2, _scroll.y() + _scroll.height() - _toHistoryEnd.height() - st::historyToEndSkip);
 | 
			
		||||
	updateCollapseCommentsVisibility();
 | 
			
		||||
 | 
			
		||||
	_send.move(width() - _send.width(), _attachDocument.y());
 | 
			
		||||
	_botStart.setGeometry(0, _attachDocument.y(), width(), _botStart.height());
 | 
			
		||||
| 
						 | 
				
			
			@ -4950,6 +5085,7 @@ void HistoryWidget::updateListSize(int32 addToY, bool initial, bool loadedDown,
 | 
			
		|||
		_scroll.resize(width(), newScrollHeight);
 | 
			
		||||
		_attachMention.setBoundings(_scroll.geometry());
 | 
			
		||||
		_toHistoryEnd.move((width() - _toHistoryEnd.width()) / 2, _scroll.y() + _scroll.height() - _toHistoryEnd.height() - st::historyToEndSkip);
 | 
			
		||||
		updateCollapseCommentsVisibility();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!initial) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4984,7 +5120,7 @@ void HistoryWidget::updateListSize(int32 addToY, bool initial, bool loadedDown,
 | 
			
		|||
		_histInited = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int32 toY = History::ScrollMax;
 | 
			
		||||
	int32 toY = ScrollMax;
 | 
			
		||||
	if (initial && _history->lastWidth) {
 | 
			
		||||
		toY = newSt;
 | 
			
		||||
		_history->lastWidth = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -5000,6 +5136,37 @@ void HistoryWidget::updateListSize(int32 addToY, bool initial, bool loadedDown,
 | 
			
		|||
			_animActiveTimer.start(AnimationTimerDelta);
 | 
			
		||||
			_activeAnimMsgId = _showAtMsgId;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (initial && _fixedInScrollMsgId > 0) {
 | 
			
		||||
		HistoryItem *item = App::histItemById(_channel, _fixedInScrollMsgId);
 | 
			
		||||
		if (!item || item->detached()) {
 | 
			
		||||
			item = 0;
 | 
			
		||||
			for (int32 blockIndex = 0, blocksCount = _history->blocks.size(); blockIndex < blocksCount; ++blockIndex) {
 | 
			
		||||
				HistoryBlock *block = _history->blocks.at(blockIndex);
 | 
			
		||||
				for (int32 itemIndex = 0, itemsCount = block->items.size(); itemIndex < itemsCount; ++itemIndex) {
 | 
			
		||||
					item = block->items.at(itemIndex);
 | 
			
		||||
					if (item->id > _fixedInScrollMsgId) {
 | 
			
		||||
						break;
 | 
			
		||||
					} else if (item->id < 0) {
 | 
			
		||||
						if (item->type() == HistoryItemGroup && qMax(static_cast<HistoryGroup*>(item)->minId(), 1) >= _fixedInScrollMsgId) {
 | 
			
		||||
							break;
 | 
			
		||||
						} else if (item->type() == HistoryItemCollapse && static_cast<HistoryCollapse*>(item)->wasMinId() >= _fixedInScrollMsgId) {
 | 
			
		||||
							break;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (item) {
 | 
			
		||||
				toY = qMax(firstItemY + item->y + item->block()->y - _fixedInScrollMsgTop, 0);
 | 
			
		||||
			} else {
 | 
			
		||||
				_showAtMsgId = ShowAtUnreadMsgId;
 | 
			
		||||
				_fixedInScrollMsgId = 0;
 | 
			
		||||
				_fixedInScrollMsgTop = 0;
 | 
			
		||||
				_histInited = false;
 | 
			
		||||
				return updateListSize(addToY, initial);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			toY = qMax(firstItemY + item->y + item->block()->y + item->height() - _fixedInScrollMsgTop, 0);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (initial && _history->unreadBar) {
 | 
			
		||||
		toY = firstItemY + _history->unreadBar->y + _history->unreadBar->block()->y;
 | 
			
		||||
	} else if (_history->showFrom) {
 | 
			
		||||
| 
						 | 
				
			
			@ -5017,17 +5184,17 @@ void HistoryWidget::updateListSize(int32 addToY, bool initial, bool loadedDown,
 | 
			
		|||
	_scroll.scrollToY(toY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::addMessagesToFront(const QVector<MTPMessage> &messages) {
 | 
			
		||||
void HistoryWidget::addMessagesToFront(const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed) {
 | 
			
		||||
	int32 oldH = _history->height;
 | 
			
		||||
	_list->messagesReceived(messages);
 | 
			
		||||
	_list->messagesReceived(messages, collapsed);
 | 
			
		||||
	if (!_firstLoadRequest) {
 | 
			
		||||
		updateListSize(_history->height - oldH);
 | 
			
		||||
		updateBotKeyboard();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::addMessagesToBack(const QVector<MTPMessage> &messages) {
 | 
			
		||||
	_list->messagesReceivedDown(messages);
 | 
			
		||||
void HistoryWidget::addMessagesToBack(const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed) {
 | 
			
		||||
	_list->messagesReceivedDown(messages, collapsed);
 | 
			
		||||
	if (!_firstLoadRequest) {
 | 
			
		||||
		updateListSize(0, false, true);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -5038,22 +5205,7 @@ void HistoryWidget::countHistoryShowFrom() {
 | 
			
		|||
		_history->showFrom = 0;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if (_history->showFrom) return;
 | 
			
		||||
 | 
			
		||||
	bool greaterFound = false;
 | 
			
		||||
	for (History::const_iterator i = _history->cend(); i != _history->cbegin();) {
 | 
			
		||||
		--i;
 | 
			
		||||
		for (HistoryBlock::const_iterator j = (*i)->cend(); j != (*i)->cbegin();) {
 | 
			
		||||
			--j;
 | 
			
		||||
			if ((*j)->itemType() == HistoryItem::MsgType && (*j)->id > 0) {
 | 
			
		||||
				if ((*j)->id >= _history->inboxReadBefore) {
 | 
			
		||||
					_history->showFrom = *j;
 | 
			
		||||
				} else {
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	_history->updateShowFrom();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::updateBotKeyboard() {
 | 
			
		||||
| 
						 | 
				
			
			@ -5138,6 +5290,29 @@ void HistoryWidget::updateToEndVisibility() {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::updateCollapseCommentsVisibility() {
 | 
			
		||||
	int32 collapseCommentsLeft = (width() - _collapseComments.width()) / 2, collapseCommentsTop = st::msgServiceMargin.top();
 | 
			
		||||
	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 (_collapseComments.x() != collapseCommentsLeft || _collapseComments.y() != collapseCommentsTop) {
 | 
			
		||||
		_collapseComments.move(collapseCommentsLeft, collapseCommentsTop);
 | 
			
		||||
	}
 | 
			
		||||
	if (collapseCommentsVisible && _collapseComments.isHidden()) {
 | 
			
		||||
		_collapseComments.show();
 | 
			
		||||
	} else if (!collapseCommentsVisible && !_collapseComments.isHidden()) {
 | 
			
		||||
		_collapseComments.hide();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::mousePressEvent(QMouseEvent *e) {
 | 
			
		||||
	_replyForwardPressed = QRect(0, _field.y() - st::sendPadding - st::replyHeight, st::replySkip, st::replyHeight).contains(e->pos());
 | 
			
		||||
	if (_replyForwardPressed && !_replyForwardPreviewCancel.isHidden()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -5250,7 +5425,7 @@ void HistoryWidget::onStickerSend(DocumentData *sticker) {
 | 
			
		|||
	} else {
 | 
			
		||||
		flags |= MTPDmessage::flag_from_id;
 | 
			
		||||
	}
 | 
			
		||||
	_history->addToBackDocument(newId.msg, flags, replyToId(), date(MTP_int(unixtime())), fromChannelName ? 0 : MTP::authedId(), sticker);
 | 
			
		||||
	_history->addNewDocument(newId.msg, flags, replyToId(), date(MTP_int(unixtime())), fromChannelName ? 0 : MTP::authedId(), sticker);
 | 
			
		||||
 | 
			
		||||
	_history->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), _peer->input, MTP_int(replyToId()), MTP_inputMediaDocument(MTP_inputDocument(MTP_long(sticker->id), MTP_long(sticker->access))), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, _history->sendRequestId);
 | 
			
		||||
	App::main()->finishForwarding(_history);
 | 
			
		||||
| 
						 | 
				
			
			@ -5571,10 +5746,6 @@ void HistoryWidget::onDeleteSelectedSure() {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!ids.isEmpty()) {
 | 
			
		||||
		App::main()->deleteMessages(_peer, ids);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	onClearSelected();
 | 
			
		||||
	for (SelectedItemSet::const_iterator i = sel.cbegin(), e = sel.cend(); i != e; ++i) {
 | 
			
		||||
		i.value()->destroy();
 | 
			
		||||
| 
						 | 
				
			
			@ -5583,22 +5754,34 @@ void HistoryWidget::onDeleteSelectedSure() {
 | 
			
		|||
		App::main()->itemResized(0);
 | 
			
		||||
	}
 | 
			
		||||
	App::wnd()->hideLayer();
 | 
			
		||||
 | 
			
		||||
	if (!ids.isEmpty()) {
 | 
			
		||||
		App::main()->deleteMessages(_peer, ids);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::onDeleteContextSure() {
 | 
			
		||||
	HistoryItem *item = App::contextItem();
 | 
			
		||||
	if (!item || item->itemType() != HistoryItem::MsgType) {
 | 
			
		||||
	if (!item || item->type() != HistoryItemMsg) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (item->id > 0) {
 | 
			
		||||
		App::main()->deleteMessages(item->history()->peer, QVector<MTPint>(1, MTP_int(item->id)));
 | 
			
		||||
	}
 | 
			
		||||
	QVector<MTPint> toDelete(1, MTP_int(item->id));
 | 
			
		||||
	History *h = item->history();
 | 
			
		||||
	bool wasOnServer = (item->id > 0), wasLast = (h->lastMsg == item);
 | 
			
		||||
	item->destroy();
 | 
			
		||||
	if (!wasOnServer && wasLast && !h->lastMsg) {
 | 
			
		||||
		App::main()->checkPeerHistory(h->peer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (App::main() && App::main()->peer() == peer()) {
 | 
			
		||||
		App::main()->itemResized(0);
 | 
			
		||||
	}
 | 
			
		||||
	App::wnd()->hideLayer();
 | 
			
		||||
 | 
			
		||||
	if (wasOnServer) {
 | 
			
		||||
		App::main()->deleteMessages(h->peer, toDelete);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryWidget::onListEscapePressed() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,8 +37,8 @@ public:
 | 
			
		|||
 | 
			
		||||
	HistoryList(HistoryWidget *historyWidget, ScrollArea *scroll, History *history);
 | 
			
		||||
 | 
			
		||||
	void messagesReceived(const QVector<MTPMessage> &messages);
 | 
			
		||||
	void messagesReceivedDown(const QVector<MTPMessage> &messages);
 | 
			
		||||
	void messagesReceived(const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed);
 | 
			
		||||
	void messagesReceivedDown(const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed);
 | 
			
		||||
 | 
			
		||||
	bool event(QEvent *e); // calls touchEvent when necessary
 | 
			
		||||
	void touchEvent(QTouchEvent *e);
 | 
			
		||||
| 
						 | 
				
			
			@ -84,6 +84,8 @@ public:
 | 
			
		|||
	bool wasSelectedText() const;
 | 
			
		||||
	void setFirstLoading(bool loading);
 | 
			
		||||
 | 
			
		||||
	HistoryItem *atTopImportantMsg(int32 top, int32 height, int32 &bottomUnderScrollTop) const;
 | 
			
		||||
 | 
			
		||||
	~HistoryList();
 | 
			
		||||
	
 | 
			
		||||
public slots:
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +117,7 @@ private:
 | 
			
		|||
	void touchUpdateSpeed();
 | 
			
		||||
	void touchDeaccelerate(int32 elapsed);
 | 
			
		||||
 | 
			
		||||
	void adjustCurrent(int32 y);
 | 
			
		||||
	void adjustCurrent(int32 y) const;
 | 
			
		||||
	HistoryItem *prevItem(HistoryItem *item);
 | 
			
		||||
	HistoryItem *nextItem(HistoryItem *item);
 | 
			
		||||
	void updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dragSelTo, bool dragSelecting, bool force = false);
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +131,7 @@ private:
 | 
			
		|||
 | 
			
		||||
	HistoryWidget *historyWidget;
 | 
			
		||||
	ScrollArea *scrollArea;
 | 
			
		||||
	int32 currentBlock, currentItem;
 | 
			
		||||
	mutable int32 currentBlock, currentItem;
 | 
			
		||||
 | 
			
		||||
	bool _firstLoading;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -370,6 +372,14 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class CollapseButton : public FlatButton {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	CollapseButton(QWidget *parent);
 | 
			
		||||
	void paintEvent(QPaintEvent *e);
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class HistoryWidget : public TWidget, public RPCSender {
 | 
			
		||||
	Q_OBJECT
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -449,6 +459,7 @@ public:
 | 
			
		|||
 | 
			
		||||
	PeerData *peer() const;
 | 
			
		||||
	MsgId msgId() const;
 | 
			
		||||
	HistoryItem *atTopImportantMsg(int32 &bottomUnderScrollTop) const;
 | 
			
		||||
 | 
			
		||||
	void animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false);
 | 
			
		||||
	bool showStep(float64 ms);
 | 
			
		||||
| 
						 | 
				
			
			@ -514,6 +525,7 @@ public:
 | 
			
		|||
 | 
			
		||||
	void contactsReceived();
 | 
			
		||||
	void updateToEndVisibility();
 | 
			
		||||
	void updateCollapseCommentsVisibility();
 | 
			
		||||
 | 
			
		||||
	void updateAfterDrag();
 | 
			
		||||
	void ctrlEnterSubmitUpdated();
 | 
			
		||||
| 
						 | 
				
			
			@ -565,6 +577,7 @@ public slots:
 | 
			
		|||
 | 
			
		||||
	void onListScroll();
 | 
			
		||||
	void onHistoryToEnd();
 | 
			
		||||
	void onCollapseComments();
 | 
			
		||||
	void onSend(bool ctrlShiftEnter = false, MsgId replyTo = -1);
 | 
			
		||||
	void onUnblock();
 | 
			
		||||
	void onBotStart();
 | 
			
		||||
| 
						 | 
				
			
			@ -653,8 +666,8 @@ private:
 | 
			
		|||
 | 
			
		||||
	bool messagesFailed(const RPCError &error, mtpRequestId requestId);
 | 
			
		||||
	void updateListSize(int32 addToY = 0, bool initial = false, bool loadedDown = false, HistoryItem *resizedItem = 0, bool scrollToIt = false);
 | 
			
		||||
	void addMessagesToFront(const QVector<MTPMessage> &messages);
 | 
			
		||||
	void addMessagesToBack(const QVector<MTPMessage> &messages);
 | 
			
		||||
	void addMessagesToFront(const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed);
 | 
			
		||||
	void addMessagesToBack(const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed);
 | 
			
		||||
 | 
			
		||||
	void reportSpamDone(PeerData *peer, const MTPBool &result, mtpRequestId request);
 | 
			
		||||
	bool reportSpamFail(const RPCError &error, mtpRequestId request);
 | 
			
		||||
| 
						 | 
				
			
			@ -683,7 +696,8 @@ private:
 | 
			
		|||
	PeerData *_peer, *_clearPeer; // cache _peer in _clearPeer when showing clear history box
 | 
			
		||||
	ChannelId _channel;
 | 
			
		||||
	bool _canSendMessages;
 | 
			
		||||
	MsgId _showAtMsgId;
 | 
			
		||||
	MsgId _showAtMsgId, _fixedInScrollMsgId;
 | 
			
		||||
	int32 _fixedInScrollMsgTop;
 | 
			
		||||
 | 
			
		||||
	mtpRequestId _firstLoadRequest, _preloadRequest, _preloadDownRequest;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -698,6 +712,7 @@ private:
 | 
			
		|||
	bool _histInited; // initial updateListSize() called
 | 
			
		||||
 | 
			
		||||
	IconedButton _toHistoryEnd;
 | 
			
		||||
	CollapseButton _collapseComments;
 | 
			
		||||
 | 
			
		||||
	MentionsDropdown _attachMention;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -543,7 +543,7 @@ void MainWidget::finishForwarding(History *hist) {
 | 
			
		|||
			if (genClientSideMessage) {
 | 
			
		||||
				FullMsgId newId(peerToChannel(hist->peer->id), clientMsgId());
 | 
			
		||||
				HistoryMessage *msg = static_cast<HistoryMessage*>(_toForward.cbegin().value());
 | 
			
		||||
				hist->addToBackForwarded(newId.msg, date(MTP_int(unixtime())), hist->peer->isChannel() ? 0 : MTP::authedId(), msg);
 | 
			
		||||
				hist->addNewForwarded(newId.msg, date(MTP_int(unixtime())), hist->peer->isChannel() ? 0 : MTP::authedId(), msg);
 | 
			
		||||
				if (HistorySticker *sticker = dynamic_cast<HistorySticker*>(msg->getMedia())) {
 | 
			
		||||
					App::main()->incrementSticker(sticker->document());
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -760,7 +760,10 @@ bool MainWidget::leaveChatFailed(PeerData *peer, const RPCError &error) {
 | 
			
		|||
			showDialogs();
 | 
			
		||||
		}
 | 
			
		||||
		dialogs.removePeer(peer);
 | 
			
		||||
		App::history(peer->id)->clear();
 | 
			
		||||
		if (History *h = App::historyLoaded(peer->id)) {
 | 
			
		||||
			h->clear();
 | 
			
		||||
			h->newLoaded = h->oldLoaded = true;
 | 
			
		||||
		}
 | 
			
		||||
		MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer));
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -773,7 +776,10 @@ void MainWidget::deleteHistoryAfterLeave(PeerData *peer, const MTPUpdates &updat
 | 
			
		|||
		showDialogs();
 | 
			
		||||
	}
 | 
			
		||||
	dialogs.removePeer(peer);
 | 
			
		||||
	App::history(peer->id)->clear();
 | 
			
		||||
	if (History *h = App::historyLoaded(peer->id)) {
 | 
			
		||||
		h->clear();
 | 
			
		||||
		h->newLoaded = h->oldLoaded = true;
 | 
			
		||||
	}
 | 
			
		||||
	MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -809,20 +815,22 @@ void MainWidget::deletedContact(UserData *user, const MTPcontacts_Link &result)
 | 
			
		|||
 | 
			
		||||
void MainWidget::deleteConversation(PeerData *peer) {
 | 
			
		||||
	dialogs.removePeer(peer);
 | 
			
		||||
	History *h = App::history(peer->id);
 | 
			
		||||
	h->clear();
 | 
			
		||||
	h->newLoaded = h->oldLoaded = true;
 | 
			
		||||
	if (History *h = App::historyLoaded(peer->id)) {
 | 
			
		||||
		h->clear();
 | 
			
		||||
		h->newLoaded = h->oldLoaded = true;
 | 
			
		||||
	}
 | 
			
		||||
	showDialogs();
 | 
			
		||||
	MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWidget::clearHistory(PeerData *peer) {
 | 
			
		||||
	History *h = App::history(peer->id);
 | 
			
		||||
	if (h->lastMsg) {
 | 
			
		||||
		Local::addSavedPeer(h->peer, h->lastMsg->date);
 | 
			
		||||
	if (History *h = App::historyLoaded(peer->id)) {
 | 
			
		||||
		if (h->lastMsg) {
 | 
			
		||||
			Local::addSavedPeer(h->peer, h->lastMsg->date);
 | 
			
		||||
		}
 | 
			
		||||
		h->clear();
 | 
			
		||||
		h->newLoaded = h->oldLoaded = true;
 | 
			
		||||
	}
 | 
			
		||||
	h->clear();
 | 
			
		||||
	h->newLoaded = h->oldLoaded = true;
 | 
			
		||||
	showPeerHistory(peer->id, ShowAtUnreadMsgId);
 | 
			
		||||
	MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -919,7 +927,7 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu
 | 
			
		|||
		if (peer && peer->isChannel()) {
 | 
			
		||||
			peer->asChannel()->ptsReceived(d.vpts.v);
 | 
			
		||||
		} else {
 | 
			
		||||
			LOG(("App Error: received messages.channelMessages in MainWidget::checkedHistory when no channel was passed!"));
 | 
			
		||||
			LOG(("API Error: received messages.channelMessages when no channel was passed! (MainWidget::checkedHistory)"));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
| 
						 | 
				
			
			@ -930,11 +938,11 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu
 | 
			
		|||
	if (!v) return;
 | 
			
		||||
 | 
			
		||||
	if (v->isEmpty()) {
 | 
			
		||||
		if ((profile && profile->peer() == peer) || (overview && overview->peer() == peer) || _stack.contains(peer) || history.peer() == peer) {
 | 
			
		||||
			showDialogs();
 | 
			
		||||
		}
 | 
			
		||||
		if (peer->isChat() && peer->asChat()->left) {
 | 
			
		||||
			dialogs.removePeer(peer);
 | 
			
		||||
			if (history.peer() == peer) {
 | 
			
		||||
				showDialogs();
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			History *h = App::historyLoaded(peer->id);
 | 
			
		||||
			if (h) Local::addSavedPeer(peer, h->lastMsgDate);
 | 
			
		||||
| 
						 | 
				
			
			@ -942,7 +950,7 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu
 | 
			
		|||
	} else {
 | 
			
		||||
		History *h = App::historyLoaded(peer->id);
 | 
			
		||||
		if (!h->lastMsg) {
 | 
			
		||||
			h->addToBack((*v)[0], 0);
 | 
			
		||||
			h->addNewMessage((*v)[0], 0);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -975,6 +983,7 @@ bool MainWidget::sendMessageFail(const RPCError &error) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void MainWidget::onResendAsDocument() {
 | 
			
		||||
	QMap<History*, bool> historiesToCheck;
 | 
			
		||||
	QList<uint64> tmp = _resendImgRandomIds;
 | 
			
		||||
	_resendImgRandomIds.clear();
 | 
			
		||||
	for (int32 i = 0, l = tmp.size(); i < l; ++i) {
 | 
			
		||||
| 
						 | 
				
			
			@ -989,20 +998,33 @@ void MainWidget::onResendAsDocument() {
 | 
			
		|||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			History *h = item->history();
 | 
			
		||||
			bool wasLast = (h->lastMsg == item);
 | 
			
		||||
			item->destroy();
 | 
			
		||||
			if (wasLast && !h->lastMsg) historiesToCheck.insert(h, true);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for (QMap<History*, bool>::const_iterator i = historiesToCheck.cbegin(), e = historiesToCheck.cend(); i != e; ++i) {
 | 
			
		||||
		checkPeerHistory(i.key()->peer);
 | 
			
		||||
	}
 | 
			
		||||
	App::wnd()->hideLayer(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWidget::onCancelResend() {
 | 
			
		||||
	QMap<History*, bool> historiesToCheck;
 | 
			
		||||
	QList<uint64> tmp = _resendImgRandomIds;
 | 
			
		||||
	_resendImgRandomIds.clear();
 | 
			
		||||
	for (int32 i = 0, l = tmp.size(); i < l; ++i) {
 | 
			
		||||
		if (HistoryItem *item = App::histItemById(App::histItemByRandom(tmp.at(i)))) {
 | 
			
		||||
			History *h = item->history();
 | 
			
		||||
			bool wasLast = (h->lastMsg == item);
 | 
			
		||||
			item->destroy();
 | 
			
		||||
			if (wasLast && !h->lastMsg) historiesToCheck.insert(h, true);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for (QMap<History*, bool>::const_iterator i = historiesToCheck.cbegin(), e = historiesToCheck.cend(); i != e; ++i) {
 | 
			
		||||
		checkPeerHistory(i.key()->peer);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWidget::onCacheBackground() {
 | 
			
		||||
| 
						 | 
				
			
			@ -1149,7 +1171,7 @@ void MainWidget::sendPreparedText(History *hist, const QString &text, MsgId repl
 | 
			
		|||
			flags |= MTPDmessage::flag_from_id;
 | 
			
		||||
		}
 | 
			
		||||
		MTPVector<MTPMessageEntity> localEntities = linksToMTP(textParseLinks(sendingText, itemTextParseOptions(hist, App::self()).flags));
 | 
			
		||||
		hist->addToBack(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)));
 | 
			
		||||
		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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1157,7 +1179,9 @@ void MainWidget::sendPreparedText(History *hist, const QString &text, MsgId repl
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void MainWidget::sendMessage(History *hist, const QString &text, MsgId replyTo) {
 | 
			
		||||
	hist->getReadyFor(ShowAtTheEndMsgId);
 | 
			
		||||
	MsgId fixInScrollMsgId = 0;
 | 
			
		||||
	int32 fixInScrollMsgTop = 0;
 | 
			
		||||
	hist->getReadyFor(ShowAtTheEndMsgId, fixInScrollMsgId, fixInScrollMsgTop);
 | 
			
		||||
	readServerHistory(hist, false);
 | 
			
		||||
	sendPreparedText(hist, history.prepareMessage(text), replyTo);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1233,7 +1257,7 @@ void MainWidget::preloadOverviews(PeerData *peer) {
 | 
			
		|||
	History *h = App::history(peer->id);
 | 
			
		||||
	bool sending[OverviewCount] = { false };
 | 
			
		||||
	for (int32 i = 0; i < OverviewCount; ++i) {
 | 
			
		||||
		if (h->_overviewCount[i] < 0) {
 | 
			
		||||
		if (h->overviewCount[i] < 0) {
 | 
			
		||||
			if (_overviewPreload[i].constFind(peer) == _overviewPreload[i].cend()) {
 | 
			
		||||
				sending[i] = true;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -1274,14 +1298,14 @@ void MainWidget::overviewPreloaded(PeerData *peer, const MTPmessages_Messages &r
 | 
			
		|||
		const MTPDmessages_messages &d(result.c_messages_messages());
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
		App::feedChats(d.vchats);
 | 
			
		||||
		h->_overviewCount[type] = d.vmessages.c_vector().v.size();
 | 
			
		||||
		h->overviewCount[type] = d.vmessages.c_vector().v.size();
 | 
			
		||||
	} break;
 | 
			
		||||
 | 
			
		||||
	case mtpc_messages_messagesSlice: {
 | 
			
		||||
		const MTPDmessages_messagesSlice &d(result.c_messages_messagesSlice());
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
		App::feedChats(d.vchats);
 | 
			
		||||
		h->_overviewCount[type] = d.vcount.v;
 | 
			
		||||
		h->overviewCount[type] = d.vcount.v;
 | 
			
		||||
	} break;
 | 
			
		||||
 | 
			
		||||
	case mtpc_messages_channelMessages: {
 | 
			
		||||
| 
						 | 
				
			
			@ -1289,21 +1313,24 @@ void MainWidget::overviewPreloaded(PeerData *peer, const MTPmessages_Messages &r
 | 
			
		|||
		if (peer && peer->isChannel()) {
 | 
			
		||||
			peer->asChannel()->ptsReceived(d.vpts.v);
 | 
			
		||||
		} else {
 | 
			
		||||
			LOG(("App Error: received messages.channelMessages in MainWidget::overviewPreloaded when no channel was passed!"));
 | 
			
		||||
			LOG(("API Error: received messages.channelMessages when no channel was passed! (MainWidget::overviewPreloaded)"));
 | 
			
		||||
		}
 | 
			
		||||
		if (d.has_collapsed()) { // should not be returned
 | 
			
		||||
			LOG(("API Error: channels.getMessages and messages.getMessages should not return collapsed groups! (MainWidget::overviewPreloaded)"));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
		App::feedChats(d.vchats);
 | 
			
		||||
		h->_overviewCount[type] = d.vcount.v;
 | 
			
		||||
		h->overviewCount[type] = d.vcount.v;
 | 
			
		||||
	} break;
 | 
			
		||||
 | 
			
		||||
	default: return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (h->_overviewCount[type] > 0) {
 | 
			
		||||
		for (History::MediaOverviewIds::const_iterator i = h->_overviewIds[type].cbegin(), e = h->_overviewIds[type].cend(); i != e; ++i) {
 | 
			
		||||
	if (h->overviewCount[type] > 0) {
 | 
			
		||||
		for (History::MediaOverviewIds::const_iterator i = h->overviewIds[type].cbegin(), e = h->overviewIds[type].cend(); i != e; ++i) {
 | 
			
		||||
			if (i.key() < 0) {
 | 
			
		||||
				++h->_overviewCount[type];
 | 
			
		||||
				++h->overviewCount[type];
 | 
			
		||||
			} else {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -1323,7 +1350,7 @@ void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
 | 
			
		|||
		History *h = peer ? App::historyLoaded(peer->id) : 0;
 | 
			
		||||
		if (h) {
 | 
			
		||||
			for (int32 i = 0; i < OverviewCount; ++i) {
 | 
			
		||||
				if (!h->_overview[i].isEmpty() || h->_overviewCount[i] > 0 || i == overview->type()) {
 | 
			
		||||
				if (!h->overview[i].isEmpty() || h->overviewCount[i] > 0 || i == overview->type()) {
 | 
			
		||||
					mask |= (1 << i);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -1420,20 +1447,20 @@ void MainWidget::loadMediaBack(PeerData *peer, MediaOverviewType type, bool many
 | 
			
		|||
 | 
			
		||||
	MsgId minId = 0;
 | 
			
		||||
	History *hist = App::history(peer->id);
 | 
			
		||||
	if (hist->_overviewCount[type] == 0) return; // all loaded
 | 
			
		||||
	if (hist->overviewCount[type] == 0) return; // all loaded
 | 
			
		||||
 | 
			
		||||
	for (History::MediaOverviewIds::const_iterator i = hist->_overviewIds[type].cbegin(), e = hist->_overviewIds[type].cend(); i != e; ++i) {
 | 
			
		||||
	for (History::MediaOverviewIds::const_iterator i = hist->overviewIds[type].cbegin(), e = hist->overviewIds[type].cend(); i != e; ++i) {
 | 
			
		||||
		if (i.key() > 0) {
 | 
			
		||||
			minId = i.key();
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	int32 limit = many ? SearchManyPerPage : (hist->_overview[type].size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage;
 | 
			
		||||
	int32 limit = many ? SearchManyPerPage : (hist->overview[type].size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage;
 | 
			
		||||
	MTPMessagesFilter filter = typeToMediaFilter(type);
 | 
			
		||||
	if (type == OverviewCount) return;
 | 
			
		||||
 | 
			
		||||
	int32 flags = peer->isChannel() ? MTPmessages_Search_flag_only_important : 0;
 | 
			
		||||
	_overviewLoad[type].insert(peer, MTP::send(MTPmessages_Search(MTP_int(flags), peer->input, MTPstring(), filter, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(minId), MTP_int(limit)), rpcDone(&MainWidget::photosLoaded, hist)));
 | 
			
		||||
	_overviewLoad[type].insert(peer, MTP::send(MTPmessages_Search(MTP_int(flags), peer->input, MTPstring(), filter, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(minId), MTP_int(limit)), rpcDone(&MainWidget::overviewLoaded, hist)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWidget::peerUsernameChanged(PeerData *peer) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1461,7 +1488,7 @@ void MainWidget::showNewGroup() {
 | 
			
		|||
	dialogs.onNewGroup();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWidget::photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req) {
 | 
			
		||||
void MainWidget::overviewLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req) {
 | 
			
		||||
	OverviewsPreload::iterator it;
 | 
			
		||||
	MediaOverviewType type = OverviewCount;
 | 
			
		||||
	for (int32 i = 0; i < OverviewCount; ++i) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1481,14 +1508,14 @@ void MainWidget::photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpR
 | 
			
		|||
		App::feedUsers(d.vusers);
 | 
			
		||||
		App::feedChats(d.vchats);
 | 
			
		||||
		v = &d.vmessages.c_vector().v;
 | 
			
		||||
		h->_overviewCount[type] = 0;
 | 
			
		||||
		h->overviewCount[type] = 0;
 | 
			
		||||
	} break;
 | 
			
		||||
 | 
			
		||||
	case mtpc_messages_messagesSlice: {
 | 
			
		||||
		const MTPDmessages_messagesSlice &d(msgs.c_messages_messagesSlice());
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
		App::feedChats(d.vchats);
 | 
			
		||||
		h->_overviewCount[type] = d.vcount.v;
 | 
			
		||||
		h->overviewCount[type] = d.vcount.v;
 | 
			
		||||
		v = &d.vmessages.c_vector().v;
 | 
			
		||||
	} break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1497,36 +1524,39 @@ void MainWidget::photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpR
 | 
			
		|||
		if (h && h->peer->isChannel()) {
 | 
			
		||||
			h->peer->asChannel()->ptsReceived(d.vpts.v);
 | 
			
		||||
		} else {
 | 
			
		||||
			LOG(("App Error: received messages.channelMessages in MainWidget::photosLoaded when no channel was passed!"));
 | 
			
		||||
			LOG(("API Error: received messages.channelMessages when no channel was passed! (MainWidget::overviewLoaded)"));
 | 
			
		||||
		}
 | 
			
		||||
		if (d.has_collapsed()) { // should not be returned
 | 
			
		||||
			LOG(("API Error: channels.getMessages and messages.getMessages should not return collapsed groups! (MainWidget::overviewLoaded)"));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
		App::feedChats(d.vchats);
 | 
			
		||||
		h->_overviewCount[type] = d.vcount.v;
 | 
			
		||||
		h->overviewCount[type] = d.vcount.v;
 | 
			
		||||
		v = &d.vmessages.c_vector().v;
 | 
			
		||||
	} break;
 | 
			
		||||
 | 
			
		||||
	default: return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (h->_overviewCount[type] > 0) {
 | 
			
		||||
		for (History::MediaOverviewIds::const_iterator i = h->_overviewIds[type].cbegin(), e = h->_overviewIds[type].cend(); i != e; ++i) {
 | 
			
		||||
	if (h->overviewCount[type] > 0) {
 | 
			
		||||
		for (History::MediaOverviewIds::const_iterator i = h->overviewIds[type].cbegin(), e = h->overviewIds[type].cend(); i != e; ++i) {
 | 
			
		||||
			if (i.key() < 0) {
 | 
			
		||||
				++h->_overviewCount[type];
 | 
			
		||||
				++h->overviewCount[type];
 | 
			
		||||
			} else {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (v->isEmpty()) {
 | 
			
		||||
		h->_overviewCount[type] = 0;
 | 
			
		||||
		h->overviewCount[type] = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (QVector<MTPMessage>::const_iterator i = v->cbegin(), e = v->cend(); i != e; ++i) {
 | 
			
		||||
		HistoryItem *item = App::histories().addToBack(*i, -1);
 | 
			
		||||
		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);
 | 
			
		||||
		HistoryItem *item = App::histories().addNewMessage(*i, -1);
 | 
			
		||||
		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);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (App::wnd()) App::wnd()->mediaOverviewUpdated(h->peer, type);
 | 
			
		||||
| 
						 | 
				
			
			@ -1580,6 +1610,11 @@ void MainWidget::messagesAffected(PeerData *peer, const MTPmessages_AffectedMess
 | 
			
		|||
	} else {
 | 
			
		||||
		ptsUpdated(d.vpts.v, d.vpts_count.v);
 | 
			
		||||
	}
 | 
			
		||||
	if (History *h = App::historyLoaded(peer->id)) {
 | 
			
		||||
		if (!h->lastMsg) {
 | 
			
		||||
			checkPeerHistory(peer);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWidget::videoLoadProgress(mtpFileLoader *loader) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1952,7 +1987,7 @@ void MainWidget::serviceNotification(const QString &msg, const MTPMessageMedia &
 | 
			
		|||
	HistoryItem *item = 0;
 | 
			
		||||
	while (textSplit(sendingText, leftText, MaxMessageSize)) {
 | 
			
		||||
		MTPVector<MTPMessageEntity> localEntities = linksToMTP(textParseLinks(sendingText, _historyTextOptions.flags));
 | 
			
		||||
		item = App::histories().addToBack(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()), unread ? 1 : 2);
 | 
			
		||||
	}
 | 
			
		||||
	if (item) {
 | 
			
		||||
		history.peerMessagesUpdated(item->history()->peer->id);
 | 
			
		||||
| 
						 | 
				
			
			@ -1977,7 +2012,10 @@ void MainWidget::serviceHistoryDone(const MTPmessages_Messages &msgs) {
 | 
			
		|||
 | 
			
		||||
	case mtpc_messages_channelMessages: {
 | 
			
		||||
		const MTPDmessages_channelMessages &d(msgs.c_messages_channelMessages());
 | 
			
		||||
		LOG(("App Error: received messages.channelMessages in MainWidget::serviceHistoryDone!"));
 | 
			
		||||
		LOG(("API Error: received messages.channelMessages! (MainWidget::serviceHistoryDone)"));
 | 
			
		||||
		if (d.has_collapsed()) { // should not be returned
 | 
			
		||||
			LOG(("API Error: channels.getMessages and messages.getMessages should not return collapsed groups! (MainWidget::serviceHistoryDone)"));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		App::feedUsers(d.vusers);
 | 
			
		||||
		App::feedChats(d.vchats);
 | 
			
		||||
| 
						 | 
				
			
			@ -2112,6 +2150,10 @@ void MainWidget::setInnerFocus() {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HistoryItem *MainWidget::atTopImportantMsg(int32 &bottomUnderScrollTop) const {
 | 
			
		||||
	return history.atTopImportantMsg(bottomUnderScrollTop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWidget::createDialogAtTop(History *history, int32 unreadCount) {
 | 
			
		||||
	dialogs.createDialogAtTop(history, unreadCount);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2844,6 +2886,10 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha
 | 
			
		|||
			h->setNotLoadedAtBottom();
 | 
			
		||||
			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;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3746,7 +3792,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().addToBack(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()));
 | 
			
		||||
		if (item) {
 | 
			
		||||
			history.peerMessagesUpdated(item->history()->peer->id);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -3767,7 +3813,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().addToBack(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()));
 | 
			
		||||
		if (item) {
 | 
			
		||||
			history.peerMessagesUpdated(item->history()->peer->id);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -3830,7 +3876,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 | 
			
		|||
			App::checkEntitiesAndViewsUpdate(d.vmessage.c_message());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		HistoryItem *item = App::histories().addToBack(d.vmessage);
 | 
			
		||||
		HistoryItem *item = App::histories().addNewMessage(d.vmessage);
 | 
			
		||||
		if (item) {
 | 
			
		||||
			history.peerMessagesUpdated(item->history()->peer->id);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -3845,14 +3891,14 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 | 
			
		|||
				App::historyUnregItem(msgRow);
 | 
			
		||||
				History *h = msgRow->history();
 | 
			
		||||
				for (int32 i = 0; i < OverviewCount; ++i) {
 | 
			
		||||
					History::MediaOverviewIds::iterator j = h->_overviewIds[i].find(msgRow->id);
 | 
			
		||||
					if (j != h->_overviewIds[i].cend()) {
 | 
			
		||||
						h->_overviewIds[i].erase(j);
 | 
			
		||||
						if (h->_overviewIds[i].constFind(d.vid.v) == h->_overviewIds[i].cend()) {
 | 
			
		||||
							h->_overviewIds[i].insert(d.vid.v, NullType());
 | 
			
		||||
							for (int32 k = 0, l = h->_overview[i].size(); k != l; ++k) {
 | 
			
		||||
								if (h->_overview[i].at(k) == msgRow->id) {
 | 
			
		||||
									h->_overview[i][k] = d.vid.v;
 | 
			
		||||
					History::MediaOverviewIds::iterator j = h->overviewIds[i].find(msgRow->id);
 | 
			
		||||
					if (j != h->overviewIds[i].cend()) {
 | 
			
		||||
						h->overviewIds[i].erase(j);
 | 
			
		||||
						if (h->overviewIds[i].constFind(d.vid.v) == h->overviewIds[i].cend()) {
 | 
			
		||||
							h->overviewIds[i].insert(d.vid.v, NullType());
 | 
			
		||||
							for (int32 k = 0, l = h->overview[i].size(); k != l; ++k) {
 | 
			
		||||
								if (h->overview[i].at(k) == msgRow->id) {
 | 
			
		||||
									h->overview[i][k] = d.vid.v;
 | 
			
		||||
									break;
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
| 
						 | 
				
			
			@ -3864,7 +3910,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 | 
			
		|||
				if (!App::historyRegItem(msgRow)) {
 | 
			
		||||
					msgUpdated(h->peer->id, msgRow);
 | 
			
		||||
				} else {
 | 
			
		||||
					bool wasLast = (h->lastMsg == msgRow);
 | 
			
		||||
					msgRow->destroy();
 | 
			
		||||
					if (wasLast && !h->lastMsg) {
 | 
			
		||||
						checkPeerHistory(h->peer);
 | 
			
		||||
					}
 | 
			
		||||
					history.peerMessagesUpdated();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -4038,7 +4088,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 | 
			
		|||
		UserData *user = App::userLoaded(d.vuser_id.v);
 | 
			
		||||
		if (user) {
 | 
			
		||||
			if (App::history(user->id)->loadedAtBottom()) {
 | 
			
		||||
				App::history(user->id)->addToBackService(clientMsgId(), date(d.vdate), lng_action_user_registered(lt_from, user->name), MTPDmessage_flag_unread);
 | 
			
		||||
				App::history(user->id)->addNewService(clientMsgId(), date(d.vdate), lng_action_user_registered(lt_from, user->name), MTPDmessage_flag_unread);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} break;
 | 
			
		||||
| 
						 | 
				
			
			@ -4131,7 +4181,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 | 
			
		|||
			App::checkEntitiesAndViewsUpdate(d.vmessage.c_message());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		HistoryItem *item = App::histories().addToBack(d.vmessage);
 | 
			
		||||
		HistoryItem *item = App::histories().addNewMessage(d.vmessage);
 | 
			
		||||
		if (item) {
 | 
			
		||||
			history.peerMessagesUpdated(item->history()->peer->id);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -389,6 +389,8 @@ public:
 | 
			
		|||
	void ctrlEnterSubmitUpdated();
 | 
			
		||||
	void setInnerFocus();
 | 
			
		||||
 | 
			
		||||
	HistoryItem *atTopImportantMsg(int32 &bottomUnderScrollTop) const;
 | 
			
		||||
 | 
			
		||||
	~MainWidget();
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
| 
						 | 
				
			
			@ -466,7 +468,7 @@ private:
 | 
			
		|||
	void readRequestDone(PeerData *peer);
 | 
			
		||||
 | 
			
		||||
	void messagesAffected(PeerData *peer, const MTPmessages_AffectedMessages &result);
 | 
			
		||||
	void photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req);
 | 
			
		||||
	void overviewLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req);
 | 
			
		||||
 | 
			
		||||
	bool _started;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -150,8 +150,8 @@ void MediaView::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
 | 
			
		|||
	if (!_photo && !_doc) return;
 | 
			
		||||
	if (_history && _history->peer == peer && type == _overview) {
 | 
			
		||||
		_index = -1;
 | 
			
		||||
		for (int i = 0, l = _history->_overview[_overview].size(); i < l; ++i) {
 | 
			
		||||
			if (_history->_overview[_overview].at(i) == _msgid) {
 | 
			
		||||
		for (int i = 0, l = _history->overview[_overview].size(); i < l; ++i) {
 | 
			
		||||
			if (_history->overview[_overview].at(i) == _msgid) {
 | 
			
		||||
				_index = i;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -290,13 +290,13 @@ void MediaView::updateControls() {
 | 
			
		|||
	}
 | 
			
		||||
	updateHeader();
 | 
			
		||||
	if (_photo || (_history && _overview == OverviewPhotos)) {
 | 
			
		||||
		_leftNavVisible = (_index > 0) || (_index == 0 && _history && _history->_overview[_overview].size() < _history->_overviewCount[_overview]);
 | 
			
		||||
		_leftNavVisible = (_index > 0) || (_index == 0 && _history && _history->overview[_overview].size() < _history->overviewCount[_overview]);
 | 
			
		||||
		_rightNavVisible = (_index >= 0) && (
 | 
			
		||||
			(_history && _index + 1 < _history->_overview[_overview].size()) ||
 | 
			
		||||
			(_history && _index + 1 < _history->overview[_overview].size()) ||
 | 
			
		||||
			(_user && (_index + 1 < _user->photos.size() || _index + 1 < _user->photosCount)));
 | 
			
		||||
	} else if (_history && _overview == OverviewDocuments) {
 | 
			
		||||
		_leftNavVisible = (_index > 0) || (_index == 0 && _history && _history->_overview[_overview].size() < _history->_overviewCount[_overview]);
 | 
			
		||||
		_rightNavVisible = (_index >= 0) && _history && (_index + 1 < _history->_overview[_overview].size());
 | 
			
		||||
		_leftNavVisible = (_index > 0) || (_index == 0 && _history && _history->overview[_overview].size() < _history->overviewCount[_overview]);
 | 
			
		||||
		_rightNavVisible = (_index >= 0) && _history && (_index + 1 < _history->overview[_overview].size());
 | 
			
		||||
	} else {
 | 
			
		||||
		_leftNavVisible = _rightNavVisible = false;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -739,14 +739,14 @@ void MediaView::showDocument(DocumentData *doc, HistoryItem *context) {
 | 
			
		|||
	if (_history) {
 | 
			
		||||
		_overview = OverviewDocuments;
 | 
			
		||||
 | 
			
		||||
		for (int i = 0, l = _history->_overview[_overview].size(); i < l; ++i) {
 | 
			
		||||
			if (_history->_overview[_overview].at(i) == _msgid) {
 | 
			
		||||
		for (int i = 0, l = _history->overview[_overview].size(); i < l; ++i) {
 | 
			
		||||
			if (_history->overview[_overview].at(i) == _msgid) {
 | 
			
		||||
				_index = i;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (_history->_overviewCount[_overview] < 0) {
 | 
			
		||||
		if (_history->overviewCount[_overview] < 0) {
 | 
			
		||||
			loadBack();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1391,9 +1391,9 @@ void MediaView::moveToNext(int32 delta) {
 | 
			
		|||
 | 
			
		||||
	int32 newIndex = _index + delta;
 | 
			
		||||
	if (_history && _overview != OverviewCount) {
 | 
			
		||||
		if (newIndex >= 0 && newIndex < _history->_overview[_overview].size()) {
 | 
			
		||||
		if (newIndex >= 0 && newIndex < _history->overview[_overview].size()) {
 | 
			
		||||
			_index = newIndex;
 | 
			
		||||
			if (HistoryItem *item = App::histItemById(_history->channelId(), _history->_overview[_overview][_index])) {
 | 
			
		||||
			if (HistoryItem *item = App::histItemById(_history->channelId(), _history->overview[_overview][_index])) {
 | 
			
		||||
				_msgid = item->id;
 | 
			
		||||
				_channel = item->channelId();
 | 
			
		||||
				_canForward = _msgid > 0 && (_channel == NoChannel);
 | 
			
		||||
| 
						 | 
				
			
			@ -1432,8 +1432,8 @@ void MediaView::preloadData(int32 delta) {
 | 
			
		|||
	if (from > to) qSwap(from, to);
 | 
			
		||||
	if (_history && _overview != OverviewCount) {
 | 
			
		||||
		for (int32 i = from; i <= to; ++i) {
 | 
			
		||||
			if (i >= 0 && i < _history->_overview[_overview].size() && i != _index) {
 | 
			
		||||
				if (HistoryItem *item = App::histItemById(_history->channelId(), _history->_overview[_overview][i])) {
 | 
			
		||||
			if (i >= 0 && i < _history->overview[_overview].size() && i != _index) {
 | 
			
		||||
				if (HistoryItem *item = App::histItemById(_history->channelId(), _history->overview[_overview][i])) {
 | 
			
		||||
					if (HistoryMedia *media = item->getMedia()) {
 | 
			
		||||
						switch (media->type()) {
 | 
			
		||||
						case MediaTypePhoto: static_cast<HistoryPhoto*>(media)->photo()->full->load(); break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1444,8 +1444,8 @@ void MediaView::preloadData(int32 delta) {
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (forget >= 0 && forget < _history->_overview[_overview].size() && forget != _index) {
 | 
			
		||||
			if (HistoryItem *item = App::histItemById(_history->channelId(), _history->_overview[_overview][forget])) {
 | 
			
		||||
		if (forget >= 0 && forget < _history->overview[_overview].size() && forget != _index) {
 | 
			
		||||
			if (HistoryItem *item = App::histItemById(_history->channelId(), _history->overview[_overview][forget])) {
 | 
			
		||||
				if (HistoryMedia *media = item->getMedia()) {
 | 
			
		||||
					switch (media->type()) {
 | 
			
		||||
					case MediaTypePhoto: static_cast<HistoryPhoto*>(media)->photo()->forget(); break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1844,14 +1844,14 @@ void MediaView::updateImage() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void MediaView::findCurrent() {
 | 
			
		||||
	for (int i = 0, l = _history->_overview[_overview].size(); i < l; ++i) {
 | 
			
		||||
		if (_history->_overview[_overview].at(i) == _msgid) {
 | 
			
		||||
	for (int i = 0, l = _history->overview[_overview].size(); i < l; ++i) {
 | 
			
		||||
		if (_history->overview[_overview].at(i) == _msgid) {
 | 
			
		||||
			_index = i;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (_history->_overviewCount[_overview] < 0 || (!_index && _history->_overviewCount[_overview] > 0)) {
 | 
			
		||||
	if (_history->overviewCount[_overview] < 0 || (!_index && _history->overviewCount[_overview] > 0)) {
 | 
			
		||||
		loadBack();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1859,7 +1859,7 @@ void MediaView::findCurrent() {
 | 
			
		|||
void MediaView::loadBack() {
 | 
			
		||||
	if (_loadRequest || _index < 0 || (_overview == OverviewCount && !_user)) return;
 | 
			
		||||
 | 
			
		||||
	if (_history && _overview != OverviewCount && _history->_overviewCount[_overview] != 0) {
 | 
			
		||||
	if (_history && _overview != OverviewCount && _history->overviewCount[_overview] != 0) {
 | 
			
		||||
		if (App::main()) App::main()->loadMediaBack(_history->peer, _overview);
 | 
			
		||||
	} else if (_user && _user->photosCount != 0) {
 | 
			
		||||
		int32 limit = (_index < MediaOverviewStartPerPage && _user->photos.size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage;
 | 
			
		||||
| 
						 | 
				
			
			@ -1907,8 +1907,8 @@ void MediaView::updateHeader() {
 | 
			
		|||
	int32 index = _index, count = 0;
 | 
			
		||||
	if (_history) {
 | 
			
		||||
		if (_overview != OverviewCount) {
 | 
			
		||||
			count = _history->_overviewCount[_overview] ? _history->_overviewCount[_overview] : _history->_overview[_overview].size();
 | 
			
		||||
			if (index >= 0) index += count - _history->_overview[_overview].size();
 | 
			
		||||
			count = _history->overviewCount[_overview] ? _history->overviewCount[_overview] : _history->overview[_overview].size();
 | 
			
		||||
			if (index >= 0) index += count - _history->overview[_overview].size();
 | 
			
		||||
		}
 | 
			
		||||
	} else if (_user) {
 | 
			
		||||
		count = _user->photosCount ? _user->photosCount : _user->photos.size();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -104,7 +104,6 @@ private:
 | 
			
		|||
	void findCurrent();
 | 
			
		||||
	void loadBack();
 | 
			
		||||
 | 
			
		||||
	void photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req);
 | 
			
		||||
	void userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mtpRequestId req);
 | 
			
		||||
	void filesLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1656,19 +1656,6 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
 | 
			
		|||
				}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
			case mtpc_messageActionChannelToggleComments:
 | 
			
		||||
				if (stage) {
 | 
			
		||||
					to.add(",\n").addSpaces(lev);
 | 
			
		||||
				} else {
 | 
			
		||||
					to.add("{ messageActionChannelToggleComments");
 | 
			
		||||
					to.add("\n").addSpaces(lev);
 | 
			
		||||
				}
 | 
			
		||||
				switch (stage) {
 | 
			
		||||
				case 0: to.add("  enabled: "); ++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;
 | 
			
		||||
 | 
			
		||||
			case mtpc_dialog:
 | 
			
		||||
				if (stage) {
 | 
			
		||||
					to.add(",\n").addSpaces(lev);
 | 
			
		||||
| 
						 | 
				
			
			@ -4599,7 +4586,9 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
 | 
			
		|||
				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("  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 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -4722,6 +4711,20 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
 | 
			
		|||
				}
 | 
			
		||||
				switch (stage) {
 | 
			
		||||
				case 0: to.add("  user_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("  date: "); ++stages.back(); types.push_back(mtpc_int); 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;
 | 
			
		||||
 | 
			
		||||
			case mtpc_channelParticipantSelf:
 | 
			
		||||
				if (stage) {
 | 
			
		||||
					to.add(",\n").addSpaces(lev);
 | 
			
		||||
				} else {
 | 
			
		||||
					to.add("{ channelParticipantSelf");
 | 
			
		||||
					to.add("\n").addSpaces(lev);
 | 
			
		||||
				}
 | 
			
		||||
				switch (stage) {
 | 
			
		||||
				case 0: to.add("  user_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("  inviter_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("  date: "); ++stages.back(); types.push_back(mtpc_int); 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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -166,7 +166,6 @@ enum {
 | 
			
		|||
	mtpc_messageActionChatDeleteUser = 0xb2ae9b0c,
 | 
			
		||||
	mtpc_messageActionChatJoinedByLink = 0xf89cf5e8,
 | 
			
		||||
	mtpc_messageActionChannelCreate = 0x95d2ac92,
 | 
			
		||||
	mtpc_messageActionChannelToggleComments = 0xf2863903,
 | 
			
		||||
	mtpc_dialog = 0xc1dd804a,
 | 
			
		||||
	mtpc_dialogChannel = 0x5b8496b2,
 | 
			
		||||
	mtpc_photoEmpty = 0x2331b22d,
 | 
			
		||||
| 
						 | 
				
			
			@ -402,7 +401,7 @@ enum {
 | 
			
		|||
	mtpc_inputChannelEmpty = 0xee8c1e86,
 | 
			
		||||
	mtpc_inputChannel = 0xafeb712e,
 | 
			
		||||
	mtpc_contacts_resolvedPeer = 0x7f077ad9,
 | 
			
		||||
	mtpc_channelParticipants = 0x57d3e762,
 | 
			
		||||
	mtpc_channelParticipants = 0xdee6d213,
 | 
			
		||||
	mtpc_messageRange = 0xae30253,
 | 
			
		||||
	mtpc_messageGroup = 0xe8346f53,
 | 
			
		||||
	mtpc_updates_channelDifferenceEmpty = 0x3e11affb,
 | 
			
		||||
| 
						 | 
				
			
			@ -411,7 +410,8 @@ enum {
 | 
			
		|||
	mtpc_channelMessagesFilterEmpty = 0x94d42ee7,
 | 
			
		||||
	mtpc_channelMessagesFilter = 0xcd77d957,
 | 
			
		||||
	mtpc_channelMessagesFilterCollapsed = 0xfa01232e,
 | 
			
		||||
	mtpc_channelParticipant = 0x506116ea,
 | 
			
		||||
	mtpc_channelParticipant = 0x15ebac1d,
 | 
			
		||||
	mtpc_channelParticipantSelf = 0xa3289a6d,
 | 
			
		||||
	mtpc_channelParticipantModerator = 0x91057fef,
 | 
			
		||||
	mtpc_channelParticipantEditor = 0x98192d61,
 | 
			
		||||
	mtpc_channelParticipantKicked = 0x8cc5e69a,
 | 
			
		||||
| 
						 | 
				
			
			@ -766,7 +766,6 @@ class MTPDmessageActionChatAddUser;
 | 
			
		|||
class MTPDmessageActionChatDeleteUser;
 | 
			
		||||
class MTPDmessageActionChatJoinedByLink;
 | 
			
		||||
class MTPDmessageActionChannelCreate;
 | 
			
		||||
class MTPDmessageActionChannelToggleComments;
 | 
			
		||||
 | 
			
		||||
class MTPdialog;
 | 
			
		||||
class MTPDdialog;
 | 
			
		||||
| 
						 | 
				
			
			@ -1156,6 +1155,7 @@ class MTPDchannelMessagesFilter;
 | 
			
		|||
 | 
			
		||||
class MTPchannelParticipant;
 | 
			
		||||
class MTPDchannelParticipant;
 | 
			
		||||
class MTPDchannelParticipantSelf;
 | 
			
		||||
class MTPDchannelParticipantModerator;
 | 
			
		||||
class MTPDchannelParticipantEditor;
 | 
			
		||||
class MTPDchannelParticipantKicked;
 | 
			
		||||
| 
						 | 
				
			
			@ -3728,18 +3728,6 @@ public:
 | 
			
		|||
		return *(const MTPDmessageActionChannelCreate*)data;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MTPDmessageActionChannelToggleComments &_messageActionChannelToggleComments() {
 | 
			
		||||
		if (!data) throw mtpErrorUninitialized();
 | 
			
		||||
		if (_type != mtpc_messageActionChannelToggleComments) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChannelToggleComments);
 | 
			
		||||
		split();
 | 
			
		||||
		return *(MTPDmessageActionChannelToggleComments*)data;
 | 
			
		||||
	}
 | 
			
		||||
	const MTPDmessageActionChannelToggleComments &c_messageActionChannelToggleComments() const {
 | 
			
		||||
		if (!data) throw mtpErrorUninitialized();
 | 
			
		||||
		if (_type != mtpc_messageActionChannelToggleComments) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChannelToggleComments);
 | 
			
		||||
		return *(const MTPDmessageActionChannelToggleComments*)data;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32 innerLength() const;
 | 
			
		||||
	mtpTypeId type() const;
 | 
			
		||||
	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons);
 | 
			
		||||
| 
						 | 
				
			
			@ -3756,7 +3744,6 @@ private:
 | 
			
		|||
	explicit MTPmessageAction(MTPDmessageActionChatDeleteUser *_data);
 | 
			
		||||
	explicit MTPmessageAction(MTPDmessageActionChatJoinedByLink *_data);
 | 
			
		||||
	explicit MTPmessageAction(MTPDmessageActionChannelCreate *_data);
 | 
			
		||||
	explicit MTPmessageAction(MTPDmessageActionChannelToggleComments *_data);
 | 
			
		||||
 | 
			
		||||
	friend MTPmessageAction MTP_messageActionEmpty();
 | 
			
		||||
	friend MTPmessageAction MTP_messageActionChatCreate(const MTPstring &_title, const MTPVector<MTPint> &_users);
 | 
			
		||||
| 
						 | 
				
			
			@ -3767,7 +3754,6 @@ private:
 | 
			
		|||
	friend MTPmessageAction MTP_messageActionChatDeleteUser(MTPint _user_id);
 | 
			
		||||
	friend MTPmessageAction MTP_messageActionChatJoinedByLink(MTPint _inviter_id);
 | 
			
		||||
	friend MTPmessageAction MTP_messageActionChannelCreate(const MTPstring &_title);
 | 
			
		||||
	friend MTPmessageAction MTP_messageActionChannelToggleComments(MTPBool _enabled);
 | 
			
		||||
 | 
			
		||||
	mtpTypeId _type;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -8277,7 +8263,7 @@ public:
 | 
			
		|||
private:
 | 
			
		||||
	explicit MTPchannelParticipants(MTPDchannelParticipants *_data);
 | 
			
		||||
 | 
			
		||||
	friend MTPchannelParticipants MTP_channelParticipants(MTPint _flags, MTPint _channel_id, const MTPChannelParticipant &_self_participant);
 | 
			
		||||
	friend MTPchannelParticipants MTP_channelParticipants(MTPint _flags, MTPint _channel_id, MTPint _participants_count, const MTPChannelParticipant &_self_participant, const MTPVector<MTPChannelParticipant> &_participants);
 | 
			
		||||
};
 | 
			
		||||
typedef MTPBoxed<MTPchannelParticipants> MTPChannelParticipants;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8467,6 +8453,18 @@ public:
 | 
			
		|||
		return *(const MTPDchannelParticipant*)data;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MTPDchannelParticipantSelf &_channelParticipantSelf() {
 | 
			
		||||
		if (!data) throw mtpErrorUninitialized();
 | 
			
		||||
		if (_type != mtpc_channelParticipantSelf) throw mtpErrorWrongTypeId(_type, mtpc_channelParticipantSelf);
 | 
			
		||||
		split();
 | 
			
		||||
		return *(MTPDchannelParticipantSelf*)data;
 | 
			
		||||
	}
 | 
			
		||||
	const MTPDchannelParticipantSelf &c_channelParticipantSelf() const {
 | 
			
		||||
		if (!data) throw mtpErrorUninitialized();
 | 
			
		||||
		if (_type != mtpc_channelParticipantSelf) throw mtpErrorWrongTypeId(_type, mtpc_channelParticipantSelf);
 | 
			
		||||
		return *(const MTPDchannelParticipantSelf*)data;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MTPDchannelParticipantModerator &_channelParticipantModerator() {
 | 
			
		||||
		if (!data) throw mtpErrorUninitialized();
 | 
			
		||||
		if (_type != mtpc_channelParticipantModerator) throw mtpErrorWrongTypeId(_type, mtpc_channelParticipantModerator);
 | 
			
		||||
| 
						 | 
				
			
			@ -8525,12 +8523,14 @@ public:
 | 
			
		|||
private:
 | 
			
		||||
	explicit MTPchannelParticipant(mtpTypeId type);
 | 
			
		||||
	explicit MTPchannelParticipant(MTPDchannelParticipant *_data);
 | 
			
		||||
	explicit MTPchannelParticipant(MTPDchannelParticipantSelf *_data);
 | 
			
		||||
	explicit MTPchannelParticipant(MTPDchannelParticipantModerator *_data);
 | 
			
		||||
	explicit MTPchannelParticipant(MTPDchannelParticipantEditor *_data);
 | 
			
		||||
	explicit MTPchannelParticipant(MTPDchannelParticipantKicked *_data);
 | 
			
		||||
	explicit MTPchannelParticipant(MTPDchannelParticipantCreator *_data);
 | 
			
		||||
 | 
			
		||||
	friend MTPchannelParticipant MTP_channelParticipant(MTPint _user_id, MTPint _inviter_id, MTPint _date);
 | 
			
		||||
	friend MTPchannelParticipant MTP_channelParticipant(MTPint _user_id, MTPint _date);
 | 
			
		||||
	friend MTPchannelParticipant MTP_channelParticipantSelf(MTPint _user_id, MTPint _inviter_id, MTPint _date);
 | 
			
		||||
	friend MTPchannelParticipant MTP_channelParticipantModerator(MTPint _user_id, MTPint _inviter_id, MTPint _date);
 | 
			
		||||
	friend MTPchannelParticipant MTP_channelParticipantEditor(MTPint _user_id, MTPint _inviter_id, MTPint _date);
 | 
			
		||||
	friend MTPchannelParticipant MTP_channelParticipantKicked(MTPint _user_id, MTPint _kicked_by, MTPint _date);
 | 
			
		||||
| 
						 | 
				
			
			@ -9889,16 +9889,6 @@ public:
 | 
			
		|||
	MTPstring vtitle;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MTPDmessageActionChannelToggleComments : public mtpDataImpl<MTPDmessageActionChannelToggleComments> {
 | 
			
		||||
public:
 | 
			
		||||
	MTPDmessageActionChannelToggleComments() {
 | 
			
		||||
	}
 | 
			
		||||
	MTPDmessageActionChannelToggleComments(MTPBool _enabled) : venabled(_enabled) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MTPBool venabled;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MTPDdialog : public mtpDataImpl<MTPDdialog> {
 | 
			
		||||
public:
 | 
			
		||||
	MTPDdialog() {
 | 
			
		||||
| 
						 | 
				
			
			@ -12140,18 +12130,22 @@ class MTPDchannelParticipants : public mtpDataImpl<MTPDchannelParticipants> {
 | 
			
		|||
public:
 | 
			
		||||
	MTPDchannelParticipants() {
 | 
			
		||||
	}
 | 
			
		||||
	MTPDchannelParticipants(MTPint _flags, MTPint _channel_id, const MTPChannelParticipant &_self_participant) : vflags(_flags), vchannel_id(_channel_id), vself_participant(_self_participant) {
 | 
			
		||||
	MTPDchannelParticipants(MTPint _flags, MTPint _channel_id, MTPint _participants_count, const MTPChannelParticipant &_self_participant, const MTPVector<MTPChannelParticipant> &_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<MTPChannelParticipant> 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<MTPDmessageRange> {
 | 
			
		||||
| 
						 | 
				
			
			@ -12259,7 +12253,18 @@ class MTPDchannelParticipant : public mtpDataImpl<MTPDchannelParticipant> {
 | 
			
		|||
public:
 | 
			
		||||
	MTPDchannelParticipant() {
 | 
			
		||||
	}
 | 
			
		||||
	MTPDchannelParticipant(MTPint _user_id, MTPint _inviter_id, MTPint _date) : vuser_id(_user_id), vinviter_id(_inviter_id), vdate(_date) {
 | 
			
		||||
	MTPDchannelParticipant(MTPint _user_id, MTPint _date) : vuser_id(_user_id), vdate(_date) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MTPint vuser_id;
 | 
			
		||||
	MTPint vdate;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MTPDchannelParticipantSelf : public mtpDataImpl<MTPDchannelParticipantSelf> {
 | 
			
		||||
public:
 | 
			
		||||
	MTPDchannelParticipantSelf() {
 | 
			
		||||
	}
 | 
			
		||||
	MTPDchannelParticipantSelf(MTPint _user_id, MTPint _inviter_id, MTPint _date) : vuser_id(_user_id), vinviter_id(_inviter_id), vdate(_date) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MTPint vuser_id;
 | 
			
		||||
| 
						 | 
				
			
			@ -21852,10 +21857,6 @@ inline uint32 MTPmessageAction::innerLength() const {
 | 
			
		|||
			const MTPDmessageActionChannelCreate &v(c_messageActionChannelCreate());
 | 
			
		||||
			return v.vtitle.innerLength();
 | 
			
		||||
		}
 | 
			
		||||
		case mtpc_messageActionChannelToggleComments: {
 | 
			
		||||
			const MTPDmessageActionChannelToggleComments &v(c_messageActionChannelToggleComments());
 | 
			
		||||
			return v.venabled.innerLength();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -21904,11 +21905,6 @@ inline void MTPmessageAction::read(const mtpPrime *&from, const mtpPrime *end, m
 | 
			
		|||
			MTPDmessageActionChannelCreate &v(_messageActionChannelCreate());
 | 
			
		||||
			v.vtitle.read(from, end);
 | 
			
		||||
		} break;
 | 
			
		||||
		case mtpc_messageActionChannelToggleComments: _type = cons; {
 | 
			
		||||
			if (!data) setData(new MTPDmessageActionChannelToggleComments());
 | 
			
		||||
			MTPDmessageActionChannelToggleComments &v(_messageActionChannelToggleComments());
 | 
			
		||||
			v.venabled.read(from, end);
 | 
			
		||||
		} break;
 | 
			
		||||
		default: throw mtpErrorUnexpected(cons, "MTPmessageAction");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -21943,10 +21939,6 @@ inline void MTPmessageAction::write(mtpBuffer &to) const {
 | 
			
		|||
			const MTPDmessageActionChannelCreate &v(c_messageActionChannelCreate());
 | 
			
		||||
			v.vtitle.write(to);
 | 
			
		||||
		} break;
 | 
			
		||||
		case mtpc_messageActionChannelToggleComments: {
 | 
			
		||||
			const MTPDmessageActionChannelToggleComments &v(c_messageActionChannelToggleComments());
 | 
			
		||||
			v.venabled.write(to);
 | 
			
		||||
		} break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
inline MTPmessageAction::MTPmessageAction(mtpTypeId type) : mtpDataOwner(0), _type(type) {
 | 
			
		||||
| 
						 | 
				
			
			@ -21960,7 +21952,6 @@ inline MTPmessageAction::MTPmessageAction(mtpTypeId type) : mtpDataOwner(0), _ty
 | 
			
		|||
		case mtpc_messageActionChatDeleteUser: setData(new MTPDmessageActionChatDeleteUser()); break;
 | 
			
		||||
		case mtpc_messageActionChatJoinedByLink: setData(new MTPDmessageActionChatJoinedByLink()); break;
 | 
			
		||||
		case mtpc_messageActionChannelCreate: setData(new MTPDmessageActionChannelCreate()); break;
 | 
			
		||||
		case mtpc_messageActionChannelToggleComments: setData(new MTPDmessageActionChannelToggleComments()); break;
 | 
			
		||||
		default: throw mtpErrorBadTypeId(type, "MTPmessageAction");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -21978,8 +21969,6 @@ inline MTPmessageAction::MTPmessageAction(MTPDmessageActionChatJoinedByLink *_da
 | 
			
		|||
}
 | 
			
		||||
inline MTPmessageAction::MTPmessageAction(MTPDmessageActionChannelCreate *_data) : mtpDataOwner(_data), _type(mtpc_messageActionChannelCreate) {
 | 
			
		||||
}
 | 
			
		||||
inline MTPmessageAction::MTPmessageAction(MTPDmessageActionChannelToggleComments *_data) : mtpDataOwner(_data), _type(mtpc_messageActionChannelToggleComments) {
 | 
			
		||||
}
 | 
			
		||||
inline MTPmessageAction MTP_messageActionEmpty() {
 | 
			
		||||
	return MTPmessageAction(mtpc_messageActionEmpty);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -22007,9 +21996,6 @@ inline MTPmessageAction MTP_messageActionChatJoinedByLink(MTPint _inviter_id) {
 | 
			
		|||
inline MTPmessageAction MTP_messageActionChannelCreate(const MTPstring &_title) {
 | 
			
		||||
	return MTPmessageAction(new MTPDmessageActionChannelCreate(_title));
 | 
			
		||||
}
 | 
			
		||||
inline MTPmessageAction MTP_messageActionChannelToggleComments(MTPBool _enabled) {
 | 
			
		||||
	return MTPmessageAction(new MTPDmessageActionChannelToggleComments(_enabled));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint32 MTPdialog::innerLength() const {
 | 
			
		||||
	switch (_type) {
 | 
			
		||||
| 
						 | 
				
			
			@ -28018,7 +28004,7 @@ inline MTPchannelParticipants::MTPchannelParticipants() : mtpDataOwner(new MTPDc
 | 
			
		|||
 | 
			
		||||
inline uint32 MTPchannelParticipants::innerLength() const {
 | 
			
		||||
	const MTPDchannelParticipants &v(c_channelParticipants());
 | 
			
		||||
	return v.vflags.innerLength() + v.vchannel_id.innerLength() + (v.has_self_participant() ? v.vself_participant.innerLength() : 0);
 | 
			
		||||
	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;
 | 
			
		||||
| 
						 | 
				
			
			@ -28030,18 +28016,22 @@ inline void MTPchannelParticipants::read(const mtpPrime *&from, const mtpPrime *
 | 
			
		|||
	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<MTPChannelParticipant>(); }
 | 
			
		||||
}
 | 
			
		||||
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, const MTPChannelParticipant &_self_participant) {
 | 
			
		||||
	return MTPchannelParticipants(new MTPDchannelParticipants(_flags, _channel_id, _self_participant));
 | 
			
		||||
inline MTPchannelParticipants MTP_channelParticipants(MTPint _flags, MTPint _channel_id, MTPint _participants_count, const MTPChannelParticipant &_self_participant, const MTPVector<MTPChannelParticipant> &_participants) {
 | 
			
		||||
	return MTPchannelParticipants(new MTPDchannelParticipants(_flags, _channel_id, _participants_count, _self_participant, _participants));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline MTPmessageRange::MTPmessageRange() : mtpDataOwner(new MTPDmessageRange()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -28284,6 +28274,10 @@ inline uint32 MTPchannelParticipant::innerLength() const {
 | 
			
		|||
	switch (_type) {
 | 
			
		||||
		case mtpc_channelParticipant: {
 | 
			
		||||
			const MTPDchannelParticipant &v(c_channelParticipant());
 | 
			
		||||
			return v.vuser_id.innerLength() + v.vdate.innerLength();
 | 
			
		||||
		}
 | 
			
		||||
		case mtpc_channelParticipantSelf: {
 | 
			
		||||
			const MTPDchannelParticipantSelf &v(c_channelParticipantSelf());
 | 
			
		||||
			return v.vuser_id.innerLength() + v.vinviter_id.innerLength() + v.vdate.innerLength();
 | 
			
		||||
		}
 | 
			
		||||
		case mtpc_channelParticipantModerator: {
 | 
			
		||||
| 
						 | 
				
			
			@ -28316,6 +28310,12 @@ inline void MTPchannelParticipant::read(const mtpPrime *&from, const mtpPrime *e
 | 
			
		|||
			if (!data) setData(new MTPDchannelParticipant());
 | 
			
		||||
			MTPDchannelParticipant &v(_channelParticipant());
 | 
			
		||||
			v.vuser_id.read(from, end);
 | 
			
		||||
			v.vdate.read(from, end);
 | 
			
		||||
		} break;
 | 
			
		||||
		case mtpc_channelParticipantSelf: _type = cons; {
 | 
			
		||||
			if (!data) setData(new MTPDchannelParticipantSelf());
 | 
			
		||||
			MTPDchannelParticipantSelf &v(_channelParticipantSelf());
 | 
			
		||||
			v.vuser_id.read(from, end);
 | 
			
		||||
			v.vinviter_id.read(from, end);
 | 
			
		||||
			v.vdate.read(from, end);
 | 
			
		||||
		} break;
 | 
			
		||||
| 
						 | 
				
			
			@ -28353,6 +28353,11 @@ inline void MTPchannelParticipant::write(mtpBuffer &to) const {
 | 
			
		|||
		case mtpc_channelParticipant: {
 | 
			
		||||
			const MTPDchannelParticipant &v(c_channelParticipant());
 | 
			
		||||
			v.vuser_id.write(to);
 | 
			
		||||
			v.vdate.write(to);
 | 
			
		||||
		} break;
 | 
			
		||||
		case mtpc_channelParticipantSelf: {
 | 
			
		||||
			const MTPDchannelParticipantSelf &v(c_channelParticipantSelf());
 | 
			
		||||
			v.vuser_id.write(to);
 | 
			
		||||
			v.vinviter_id.write(to);
 | 
			
		||||
			v.vdate.write(to);
 | 
			
		||||
		} break;
 | 
			
		||||
| 
						 | 
				
			
			@ -28383,6 +28388,7 @@ inline void MTPchannelParticipant::write(mtpBuffer &to) const {
 | 
			
		|||
inline MTPchannelParticipant::MTPchannelParticipant(mtpTypeId type) : mtpDataOwner(0), _type(type) {
 | 
			
		||||
	switch (type) {
 | 
			
		||||
		case mtpc_channelParticipant: setData(new MTPDchannelParticipant()); break;
 | 
			
		||||
		case mtpc_channelParticipantSelf: setData(new MTPDchannelParticipantSelf()); break;
 | 
			
		||||
		case mtpc_channelParticipantModerator: setData(new MTPDchannelParticipantModerator()); break;
 | 
			
		||||
		case mtpc_channelParticipantEditor: setData(new MTPDchannelParticipantEditor()); break;
 | 
			
		||||
		case mtpc_channelParticipantKicked: setData(new MTPDchannelParticipantKicked()); break;
 | 
			
		||||
| 
						 | 
				
			
			@ -28392,6 +28398,8 @@ inline MTPchannelParticipant::MTPchannelParticipant(mtpTypeId type) : mtpDataOwn
 | 
			
		|||
}
 | 
			
		||||
inline MTPchannelParticipant::MTPchannelParticipant(MTPDchannelParticipant *_data) : mtpDataOwner(_data), _type(mtpc_channelParticipant) {
 | 
			
		||||
}
 | 
			
		||||
inline MTPchannelParticipant::MTPchannelParticipant(MTPDchannelParticipantSelf *_data) : mtpDataOwner(_data), _type(mtpc_channelParticipantSelf) {
 | 
			
		||||
}
 | 
			
		||||
inline MTPchannelParticipant::MTPchannelParticipant(MTPDchannelParticipantModerator *_data) : mtpDataOwner(_data), _type(mtpc_channelParticipantModerator) {
 | 
			
		||||
}
 | 
			
		||||
inline MTPchannelParticipant::MTPchannelParticipant(MTPDchannelParticipantEditor *_data) : mtpDataOwner(_data), _type(mtpc_channelParticipantEditor) {
 | 
			
		||||
| 
						 | 
				
			
			@ -28400,8 +28408,11 @@ inline MTPchannelParticipant::MTPchannelParticipant(MTPDchannelParticipantKicked
 | 
			
		|||
}
 | 
			
		||||
inline MTPchannelParticipant::MTPchannelParticipant(MTPDchannelParticipantCreator *_data) : mtpDataOwner(_data), _type(mtpc_channelParticipantCreator) {
 | 
			
		||||
}
 | 
			
		||||
inline MTPchannelParticipant MTP_channelParticipant(MTPint _user_id, MTPint _inviter_id, MTPint _date) {
 | 
			
		||||
	return MTPchannelParticipant(new MTPDchannelParticipant(_user_id, _inviter_id, _date));
 | 
			
		||||
inline MTPchannelParticipant MTP_channelParticipant(MTPint _user_id, MTPint _date) {
 | 
			
		||||
	return MTPchannelParticipant(new MTPDchannelParticipant(_user_id, _date));
 | 
			
		||||
}
 | 
			
		||||
inline MTPchannelParticipant MTP_channelParticipantSelf(MTPint _user_id, MTPint _inviter_id, MTPint _date) {
 | 
			
		||||
	return MTPchannelParticipant(new MTPDchannelParticipantSelf(_user_id, _inviter_id, _date));
 | 
			
		||||
}
 | 
			
		||||
inline MTPchannelParticipant MTP_channelParticipantModerator(MTPint _user_id, MTPint _inviter_id, MTPint _date) {
 | 
			
		||||
	return MTPchannelParticipant(new MTPDchannelParticipantModerator(_user_id, _inviter_id, _date));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -256,7 +256,6 @@ messageActionChatAddUser#5e3cfc4b user_id:int = MessageAction;
 | 
			
		|||
messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction;
 | 
			
		||||
messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction;
 | 
			
		||||
messageActionChannelCreate#95d2ac92 title:string = MessageAction;
 | 
			
		||||
messageActionChannelToggleComments#f2863903 enabled:Bool = MessageAction;
 | 
			
		||||
 | 
			
		||||
dialog#c1dd804a peer:Peer top_message:int read_inbox_max_id:int unread_count:int notify_settings:PeerNotifySettings = Dialog;
 | 
			
		||||
dialogChannel#5b8496b2 peer:Peer top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int notify_settings:PeerNotifySettings pts:int = Dialog;
 | 
			
		||||
| 
						 | 
				
			
			@ -588,7 +587,7 @@ inputChannel#afeb712e channel_id:int access_hash:long = InputChannel;
 | 
			
		|||
 | 
			
		||||
contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer;
 | 
			
		||||
 | 
			
		||||
channelParticipants#57d3e762 flags:# channel_id:int self_participant:flags.0?ChannelParticipant = ChannelParticipants;
 | 
			
		||||
channelParticipants#dee6d213 flags:# channel_id:int participants_count:int self_participant:flags.0?ChannelParticipant participants:flags.1?Vector<ChannelParticipant> = ChannelParticipants;
 | 
			
		||||
 | 
			
		||||
messageRange#ae30253 min_id:int max_id:int = MessageRange;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -602,7 +601,8 @@ channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter;
 | 
			
		|||
channelMessagesFilter#cd77d957 flags:# ranges:Vector<MessageRange> = ChannelMessagesFilter;
 | 
			
		||||
channelMessagesFilterCollapsed#fa01232e = ChannelMessagesFilter;
 | 
			
		||||
 | 
			
		||||
channelParticipant#506116ea user_id:int inviter_id:int date:int = ChannelParticipant;
 | 
			
		||||
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
 | 
			
		||||
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
 | 
			
		||||
channelParticipantModerator#91057fef user_id:int inviter_id:int date:int = ChannelParticipant;
 | 
			
		||||
channelParticipantEditor#98192d61 user_id:int inviter_id:int date:int = ChannelParticipant;
 | 
			
		||||
channelParticipantKicked#8cc5e69a user_id:int kicked_by:int date:int = ChannelParticipant;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -271,11 +271,11 @@ void OverviewInner::fixItemIndex(int32 ¤t, MsgId msgId) const {
 | 
			
		|||
	if (!msgId) {
 | 
			
		||||
		current = -1;
 | 
			
		||||
	} else if (_type == OverviewPhotos || _type == OverviewAudioDocuments) {
 | 
			
		||||
		int32 l = _hist->_overview[_type].size();
 | 
			
		||||
		if (current < 0 || current >= l || _hist->_overview[_type][current] != msgId) {
 | 
			
		||||
		int32 l = _hist->overview[_type].size();
 | 
			
		||||
		if (current < 0 || current >= l || _hist->overview[_type][current] != msgId) {
 | 
			
		||||
			current = -1;
 | 
			
		||||
			for (int32 i = 0; i < l; ++i) {
 | 
			
		||||
				if (_hist->_overview[_type][i] == msgId) {
 | 
			
		||||
				if (_hist->overview[_type][i] == msgId) {
 | 
			
		||||
					current = i;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -328,7 +328,10 @@ void OverviewInner::searchReceived(bool fromStart, const MTPmessages_Messages &r
 | 
			
		|||
			if (_peer && _peer->isChannel()) {
 | 
			
		||||
				_peer->asChannel()->ptsReceived(d.vpts.v);
 | 
			
		||||
			} else {
 | 
			
		||||
				LOG(("App Error: received messages.channelMessages in OverviewInner::searchReceived when no channel was passed!"));
 | 
			
		||||
				LOG(("API Error: received messages.channelMessages when no channel was passed! (OverviewInner::searchReceived)"));
 | 
			
		||||
			}
 | 
			
		||||
			if (d.has_collapsed()) { // should not be returned
 | 
			
		||||
				LOG(("API Error: channels.getMessages and messages.getMessages should not return collapsed groups! (OverviewInner::searchReceived)"));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			App::feedUsers(d.vusers);
 | 
			
		||||
| 
						 | 
				
			
			@ -347,7 +350,7 @@ void OverviewInner::searchReceived(bool fromStart, const MTPmessages_Messages &r
 | 
			
		|||
				_itemsToBeLoaded = LinksOverviewPerPage * 2;
 | 
			
		||||
			}
 | 
			
		||||
			for (QVector<MTPMessage>::const_iterator i = messages->cbegin(), e = messages->cend(); i != e; ++i) {
 | 
			
		||||
				HistoryItem *item = App::histories().addToBack(*i, -1);
 | 
			
		||||
				HistoryItem *item = App::histories().addNewMessage(*i, -1);
 | 
			
		||||
				_searchResults.push_front(item->id);
 | 
			
		||||
				_lastSearchId = item->id;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -454,11 +457,11 @@ void OverviewInner::moveToNextItem(MsgId &msgId, int32 &index, MsgId upTo, int32
 | 
			
		|||
 | 
			
		||||
	index += delta;
 | 
			
		||||
	if (_type == OverviewPhotos || _type == OverviewAudioDocuments) {
 | 
			
		||||
		if (index < 0 || index >= _hist->_overview[_type].size()) {
 | 
			
		||||
		if (index < 0 || index >= _hist->overview[_type].size()) {
 | 
			
		||||
			msgId = 0;
 | 
			
		||||
			index = -1;
 | 
			
		||||
		} else {
 | 
			
		||||
			msgId = _hist->_overview[_type][index];
 | 
			
		||||
			msgId = _hist->overview[_type][index];
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		while (index >= 0 && index < _items.size() && !_items[index].msgid) {
 | 
			
		||||
| 
						 | 
				
			
			@ -867,7 +870,7 @@ void OverviewInner::applyDragSelection() {
 | 
			
		|||
	}
 | 
			
		||||
	if (_dragSelecting) {
 | 
			
		||||
		for (int32 i = _dragSelToIndex; i <= _dragSelFromIndex; ++i) {
 | 
			
		||||
			MsgId msgid = (_type == OverviewPhotos || _type == OverviewAudioDocuments) ? _hist->_overview[_type][i] : _items[i].msgid;
 | 
			
		||||
			MsgId msgid = (_type == OverviewPhotos || _type == OverviewAudioDocuments) ? _hist->overview[_type][i] : _items[i].msgid;
 | 
			
		||||
			if (!msgid) continue;
 | 
			
		||||
 | 
			
		||||
			SelectedItems::iterator j = _selected.find(msgid);
 | 
			
		||||
| 
						 | 
				
			
			@ -886,7 +889,7 @@ void OverviewInner::applyDragSelection() {
 | 
			
		|||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for (int32 i = _dragSelToIndex; i <= _dragSelFromIndex; ++i) {
 | 
			
		||||
			MsgId msgid = (_type == OverviewPhotos || _type == OverviewAudioDocuments) ? _hist->_overview[_type][i] : _items[i].msgid;
 | 
			
		||||
			MsgId msgid = (_type == OverviewPhotos || _type == OverviewAudioDocuments) ? _hist->overview[_type][i] : _items[i].msgid;
 | 
			
		||||
			if (!msgid) continue;
 | 
			
		||||
 | 
			
		||||
			SelectedItems::iterator j = _selected.find(msgid);
 | 
			
		||||
| 
						 | 
				
			
			@ -933,7 +936,7 @@ void OverviewInner::clear() {
 | 
			
		|||
 | 
			
		||||
int32 OverviewInner::itemTop(const FullMsgId &msgId) const {
 | 
			
		||||
	if (_type == OverviewAudioDocuments && msgId.channel == _channel) {
 | 
			
		||||
		int32 index = _hist->_overview[_type].indexOf(msgId.msg);
 | 
			
		||||
		int32 index = _hist->overview[_type].indexOf(msgId.msg);
 | 
			
		||||
		if (index >= 0) {
 | 
			
		||||
			return _addToY + int32(index * _audioHeight);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -957,7 +960,7 @@ void OverviewInner::preloadMore() {
 | 
			
		|||
 | 
			
		||||
bool OverviewInner::preloadLocal() {
 | 
			
		||||
	if (_type != OverviewLinks) return false;
 | 
			
		||||
	if (_itemsToBeLoaded >= _hist->_overview[_type].size()) return false;
 | 
			
		||||
	if (_itemsToBeLoaded >= _hist->overview[_type].size()) return false;
 | 
			
		||||
	_itemsToBeLoaded += LinksOverviewPerPage;
 | 
			
		||||
	mediaOverviewUpdated();
 | 
			
		||||
	return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -990,7 +993,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
 | 
			
		|||
	QRect r(e->rect());
 | 
			
		||||
	p.setClipRect(r);
 | 
			
		||||
 | 
			
		||||
	if (_hist->_overview[_type].isEmpty()) {
 | 
			
		||||
	if (_hist->overview[_type].isEmpty()) {
 | 
			
		||||
		QPoint dogPos((_width - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9);
 | 
			
		||||
		p.drawPixmap(dogPos, *cChatDogImage());
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1013,7 +1016,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
 | 
			
		|||
	if (_type == OverviewPhotos) {
 | 
			
		||||
		int32 rowFrom = int32(r.top() - _addToY - st::overviewPhotoSkip) / int32(_vsize + st::overviewPhotoSkip);
 | 
			
		||||
		int32 rowTo = int32(r.bottom() - _addToY - st::overviewPhotoSkip) / int32(_vsize + st::overviewPhotoSkip) + 1;
 | 
			
		||||
		History::MediaOverview &overview(_hist->_overview[_type]);
 | 
			
		||||
		History::MediaOverview &overview(_hist->overview[_type]);
 | 
			
		||||
		int32 count = overview.size();
 | 
			
		||||
		float64 w = float64(_width - st::overviewPhotoSkip) / _photosInRow;
 | 
			
		||||
		for (int32 row = rowFrom; row < rowTo; ++row) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1096,7 +1099,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
 | 
			
		|||
	} else if (_type == OverviewAudioDocuments) {
 | 
			
		||||
		int32 from = int32(r.top() - _addToY) / int32(_audioHeight);
 | 
			
		||||
		int32 to = int32(r.bottom() - _addToY) / int32(_audioHeight) + 1;
 | 
			
		||||
		History::MediaOverview &overview(_hist->_overview[_type]);
 | 
			
		||||
		History::MediaOverview &overview(_hist->overview[_type]);
 | 
			
		||||
		int32 count = overview.size();
 | 
			
		||||
		p.translate(_audioLeft, _addToY + from * _audioHeight);
 | 
			
		||||
		for (int32 index = from; index < to; ++index) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1299,7 +1302,7 @@ void OverviewInner::onUpdateSelected() {
 | 
			
		|||
		if (row < 0) row = 0;
 | 
			
		||||
		bool upon = true;
 | 
			
		||||
 | 
			
		||||
		int32 i = row * _photosInRow + inRow - _photosToAdd, count = _hist->_overview[_type].size();
 | 
			
		||||
		int32 i = row * _photosInRow + inRow - _photosToAdd, count = _hist->overview[_type].size();
 | 
			
		||||
		if (i < 0) {
 | 
			
		||||
			i = 0;
 | 
			
		||||
			upon = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -1309,7 +1312,7 @@ void OverviewInner::onUpdateSelected() {
 | 
			
		|||
			upon = false;
 | 
			
		||||
		}
 | 
			
		||||
		if (i >= 0) {
 | 
			
		||||
			MsgId msgid = _hist->_overview[_type][i];
 | 
			
		||||
			MsgId msgid = _hist->overview[_type][i];
 | 
			
		||||
			HistoryItem *histItem = App::histItemById(_channel, msgid);
 | 
			
		||||
			if (histItem) {
 | 
			
		||||
				item = histItem;
 | 
			
		||||
| 
						 | 
				
			
			@ -1325,7 +1328,7 @@ void OverviewInner::onUpdateSelected() {
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else if (_type == OverviewAudioDocuments) {
 | 
			
		||||
		int32 i = int32((m.y() - _addToY) / _audioHeight), count = _hist->_overview[_type].size();
 | 
			
		||||
		int32 i = int32((m.y() - _addToY) / _audioHeight), count = _hist->overview[_type].size();
 | 
			
		||||
 | 
			
		||||
		bool upon = true;
 | 
			
		||||
		if (m.y() < _addToY) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1337,7 +1340,7 @@ void OverviewInner::onUpdateSelected() {
 | 
			
		|||
			upon = false;
 | 
			
		||||
		}
 | 
			
		||||
		if (i >= 0) {
 | 
			
		||||
			MsgId msgid = _hist->_overview[_type][i];
 | 
			
		||||
			MsgId msgid = _hist->overview[_type][i];
 | 
			
		||||
			HistoryItem *histItem = App::histItemById(_channel, msgid);
 | 
			
		||||
			if (histItem) {
 | 
			
		||||
				item = histItem;
 | 
			
		||||
| 
						 | 
				
			
			@ -1941,14 +1944,14 @@ void OverviewInner::goToMessage() {
 | 
			
		|||
 | 
			
		||||
void OverviewInner::forwardMessage() {
 | 
			
		||||
	HistoryItem *item = App::contextItem();
 | 
			
		||||
	if (!item || item->itemType() != HistoryItem::MsgType) return;
 | 
			
		||||
	if (!item || item->type() != HistoryItemMsg || item->serviceMsg()) return;
 | 
			
		||||
 | 
			
		||||
	App::main()->forwardLayer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OverviewInner::deleteMessage() {
 | 
			
		||||
	HistoryItem *item = App::contextItem();
 | 
			
		||||
	if (!item || item->itemType() != HistoryItem::MsgType) return;
 | 
			
		||||
	if (!item || item->type() != HistoryItemMsg) return;
 | 
			
		||||
 | 
			
		||||
	HistoryMessage *msg = item->toHistoryMessage();
 | 
			
		||||
	App::main()->deleteLayer((msg && msg->uploading()) ? -2 : -1);
 | 
			
		||||
| 
						 | 
				
			
			@ -1956,7 +1959,7 @@ void OverviewInner::deleteMessage() {
 | 
			
		|||
 | 
			
		||||
void OverviewInner::selectMessage() {
 | 
			
		||||
	HistoryItem *item = App::contextItem();
 | 
			
		||||
	if (!item || item->itemType() != HistoryItem::MsgType) return;
 | 
			
		||||
	if (!item || item->type() != HistoryItemMsg || item->serviceMsg()) return;
 | 
			
		||||
 | 
			
		||||
	if (!_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) {
 | 
			
		||||
		_selected.clear();
 | 
			
		||||
| 
						 | 
				
			
			@ -2153,7 +2156,7 @@ void OverviewInner::onTouchScrollTimer() {
 | 
			
		|||
void OverviewInner::mediaOverviewUpdated(bool fromResize) {
 | 
			
		||||
	int32 oldHeight = _height;
 | 
			
		||||
	if (_type == OverviewLinks) {
 | 
			
		||||
		History::MediaOverview &o(_inSearch ? _searchResults : _hist->_overview[_type]);
 | 
			
		||||
		History::MediaOverview &o(_inSearch ? _searchResults : _hist->overview[_type]);
 | 
			
		||||
		int32 l = o.size(), tocheck = qMin(l, _itemsToBeLoaded);
 | 
			
		||||
		_items.reserve(2 * l); // day items
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2231,7 +2234,7 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) {
 | 
			
		|||
		dragActionUpdate(QCursor::pos());
 | 
			
		||||
		update();
 | 
			
		||||
	} else if (_type != OverviewPhotos && _type != OverviewAudioDocuments) {
 | 
			
		||||
		History::MediaOverview &o(_hist->_overview[_type]);
 | 
			
		||||
		History::MediaOverview &o(_hist->overview[_type]);
 | 
			
		||||
		int32 l = o.size();
 | 
			
		||||
		_items.reserve(2 * l); // day items
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2444,9 +2447,9 @@ void OverviewInner::itemResized(HistoryItem *item, bool scrollToIt) {
 | 
			
		|||
void OverviewInner::msgUpdated(const HistoryItem *msg) {
 | 
			
		||||
	if (!msg || _hist != msg->history()) return;
 | 
			
		||||
	MsgId msgid = msg->id;
 | 
			
		||||
	if (_hist->_overviewIds[_type].constFind(msgid) != _hist->_overviewIds[_type].cend()) {
 | 
			
		||||
	if (_hist->overviewIds[_type].constFind(msgid) != _hist->overviewIds[_type].cend()) {
 | 
			
		||||
		if (_type == OverviewPhotos) {
 | 
			
		||||
			int32 index = _hist->_overview[_type].indexOf(msgid);
 | 
			
		||||
			int32 index = _hist->overview[_type].indexOf(msgid);
 | 
			
		||||
			if (index >= 0) {
 | 
			
		||||
				float64 w = (float64(width() - st::overviewPhotoSkip) / _photosInRow);
 | 
			
		||||
				int32 vsize = (_vsize + st::overviewPhotoSkip);
 | 
			
		||||
| 
						 | 
				
			
			@ -2454,7 +2457,7 @@ void OverviewInner::msgUpdated(const HistoryItem *msg) {
 | 
			
		|||
				update(int32(col * w), _addToY + int32(row * vsize), qCeil(w), vsize);
 | 
			
		||||
			}
 | 
			
		||||
		} else if (_type == OverviewAudioDocuments) {
 | 
			
		||||
			int32 index = _hist->_overview[_type].indexOf(msgid);
 | 
			
		||||
			int32 index = _hist->overview[_type].indexOf(msgid);
 | 
			
		||||
			if (index >= 0) {
 | 
			
		||||
				update(_audioLeft, _addToY + int32(index * _audioHeight), _audioWidth, _audioHeight);
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -2481,7 +2484,7 @@ void OverviewInner::showAll(bool recountHeights) {
 | 
			
		|||
	if (_type == OverviewPhotos) {
 | 
			
		||||
		_photosInRow = int32(width() - st::overviewPhotoSkip) / int32(st::overviewPhotoMinSize + st::overviewPhotoSkip);
 | 
			
		||||
		_vsize = (int32(width() - st::overviewPhotoSkip) / _photosInRow) - st::overviewPhotoSkip;
 | 
			
		||||
		int32 count = _hist->_overview[_type].size(), fullCount = _hist->_overviewCount[_type];
 | 
			
		||||
		int32 count = _hist->overview[_type].size(), fullCount = _hist->overviewCount[_type];
 | 
			
		||||
		if (fullCount > 0) {
 | 
			
		||||
			int32 cnt = count - (fullCount % _photosInRow);
 | 
			
		||||
			if (cnt < 0) cnt += _photosInRow;
 | 
			
		||||
| 
						 | 
				
			
			@ -2493,7 +2496,7 @@ void OverviewInner::showAll(bool recountHeights) {
 | 
			
		|||
		newHeight = _height = (_vsize + st::overviewPhotoSkip) * rows + st::overviewPhotoSkip;
 | 
			
		||||
		_addToY = (_height < _minHeight) ? (_minHeight - _height) : 0;
 | 
			
		||||
	} else if (_type == OverviewAudioDocuments) {
 | 
			
		||||
		int32 count = _hist->_overview[_type].size(), fullCount = _hist->_overviewCount[_type];
 | 
			
		||||
		int32 count = _hist->overview[_type].size(), fullCount = _hist->overviewCount[_type];
 | 
			
		||||
		newHeight = _height = count * _audioHeight + 2 * st::playlistPadding;
 | 
			
		||||
		_addToY = st::playlistPadding;
 | 
			
		||||
	} else if (_type == OverviewLinks) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2947,10 +2950,6 @@ void OverviewWidget::onDeleteSelectedSure() {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!ids.isEmpty()) {
 | 
			
		||||
		App::main()->deleteMessages(peer(), ids);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	onClearSelected();
 | 
			
		||||
	for (SelectedItemSet::const_iterator i = sel.cbegin(), e = sel.cend(); i != e; ++i) {
 | 
			
		||||
		i.value()->destroy();
 | 
			
		||||
| 
						 | 
				
			
			@ -2959,22 +2958,34 @@ void OverviewWidget::onDeleteSelectedSure() {
 | 
			
		|||
		App::main()->itemResized(0);
 | 
			
		||||
	}
 | 
			
		||||
	App::wnd()->hideLayer();
 | 
			
		||||
 | 
			
		||||
	if (!ids.isEmpty()) {
 | 
			
		||||
		App::main()->deleteMessages(peer(), ids);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OverviewWidget::onDeleteContextSure() {
 | 
			
		||||
	HistoryItem *item = App::contextItem();
 | 
			
		||||
	if (!item || item->itemType() != HistoryItem::MsgType) {
 | 
			
		||||
	if (!item || item->type() != HistoryItemMsg) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (item->id > 0) {
 | 
			
		||||
		App::main()->deleteMessages(item->history()->peer, QVector<MTPint>(1, MTP_int(item->id)));
 | 
			
		||||
	}
 | 
			
		||||
	QVector<MTPint> toDelete(1, MTP_int(item->id));
 | 
			
		||||
	History *h = item->history();
 | 
			
		||||
	bool wasOnServer = (item->id > 0), wasLast = (h->lastMsg == item);
 | 
			
		||||
	item->destroy();
 | 
			
		||||
	if (!wasOnServer && wasLast && !h->lastMsg) {
 | 
			
		||||
		App::main()->checkPeerHistory(h->peer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (App::main() && App::main()->peer() == peer()) {
 | 
			
		||||
		App::main()->itemResized(0);
 | 
			
		||||
	}
 | 
			
		||||
	App::wnd()->hideLayer();
 | 
			
		||||
 | 
			
		||||
	if (wasOnServer) {
 | 
			
		||||
		App::main()->deleteMessages(h->peer, toDelete);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OverviewWidget::onClearSelected() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -246,12 +246,12 @@ void PlayerWidget::updateOverRect(OverState state) {
 | 
			
		|||
void PlayerWidget::updateControls() {
 | 
			
		||||
	_fullAvailable = (_index >= 0);
 | 
			
		||||
	_prevAvailable = _fullAvailable && (_index > 0);
 | 
			
		||||
	_nextAvailable = _fullAvailable && (_index < _history->_overview[OverviewAudioDocuments].size() - 1);
 | 
			
		||||
	_nextAvailable = _fullAvailable && (_index < _history->overview[OverviewAudioDocuments].size() - 1);
 | 
			
		||||
	resizeEvent(0);
 | 
			
		||||
	update();
 | 
			
		||||
 | 
			
		||||
	if (_index >= 0 && _index < MediaOverviewStartPerPage) {
 | 
			
		||||
		if (_history->_overviewCount[OverviewAudioDocuments] < 0 || _history->_overviewCount[OverviewAudioDocuments] > 0) {
 | 
			
		||||
		if (_history->overviewCount[OverviewAudioDocuments] < 0 || _history->overviewCount[OverviewAudioDocuments] > 0) {
 | 
			
		||||
			if (App::main()) App::main()->loadMediaBack(_history->peer, OverviewAudioDocuments);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -261,7 +261,7 @@ void PlayerWidget::findCurrent() {
 | 
			
		|||
	_index = -1;
 | 
			
		||||
	if (!_history) return;
 | 
			
		||||
 | 
			
		||||
	const History::MediaOverview *o = &_history->_overview[OverviewAudioDocuments];
 | 
			
		||||
	const History::MediaOverview *o = &_history->overview[OverviewAudioDocuments];
 | 
			
		||||
	if (_history->channelId() == _song.msgId.channel) {
 | 
			
		||||
		for (int i = 0, l = o->size(); i < l; ++i) {
 | 
			
		||||
			if (o->at(i) == _song.msgId.msg) {
 | 
			
		||||
| 
						 | 
				
			
			@ -307,8 +307,8 @@ void PlayerWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type)
 | 
			
		|||
	if (_history && _history->peer == peer && type == OverviewAudioDocuments) {
 | 
			
		||||
		_index = -1;
 | 
			
		||||
		if (_history->channelId() == _song.msgId.channel) {
 | 
			
		||||
			for (int i = 0, l = _history->_overview[OverviewAudioDocuments].size(); i < l; ++i) {
 | 
			
		||||
				if (_history->_overview[OverviewAudioDocuments].at(i) == _song.msgId.msg) {
 | 
			
		||||
			for (int i = 0, l = _history->overview[OverviewAudioDocuments].size(); i < l; ++i) {
 | 
			
		||||
				if (_history->overview[OverviewAudioDocuments].at(i) == _song.msgId.msg) {
 | 
			
		||||
					_index = i;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -464,7 +464,7 @@ void PlayerWidget::playPausePressed() {
 | 
			
		|||
void PlayerWidget::prevPressed() {
 | 
			
		||||
	if (isHidden()) return;
 | 
			
		||||
 | 
			
		||||
	const History::MediaOverview *o = _history ? &_history->_overview[OverviewAudioDocuments] : 0;
 | 
			
		||||
	const History::MediaOverview *o = _history ? &_history->overview[OverviewAudioDocuments] : 0;
 | 
			
		||||
	if (audioPlayer() && o && _index > 0 && _index <= o->size() && !o->isEmpty()) {
 | 
			
		||||
		startPlay(FullMsgId(_history->channelId(), o->at(_index - 1)));
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -473,7 +473,7 @@ void PlayerWidget::prevPressed() {
 | 
			
		|||
void PlayerWidget::nextPressed() {
 | 
			
		||||
	if (isHidden()) return;
 | 
			
		||||
 | 
			
		||||
	const History::MediaOverview *o = _history ? &_history->_overview[OverviewAudioDocuments] : 0;
 | 
			
		||||
	const History::MediaOverview *o = _history ? &_history->overview[OverviewAudioDocuments] : 0;
 | 
			
		||||
	if (audioPlayer() && o && _index >= 0 && _index < o->size() - 1) {
 | 
			
		||||
		startPlay(FullMsgId(_history->channelId(), o->at(_index + 1)));
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -913,7 +913,7 @@ bool ProfileInner::updateMediaLinks(int32 *addToScroll) {
 | 
			
		|||
 | 
			
		||||
		int32 addToY = _mediaButtons[i]->height() + st::setLittleSkip;
 | 
			
		||||
 | 
			
		||||
		int32 count = (_hist->_overviewCount[i] > 0) ? _hist->_overviewCount[i] : (_hist->_overviewCount[i] == 0 ? _hist->_overview[i].size() : -1);
 | 
			
		||||
		int32 count = (_hist->overviewCount[i] > 0) ? _hist->overviewCount[i] : (_hist->overviewCount[i] == 0 ? _hist->overview[i].size() : -1);
 | 
			
		||||
		if (count > 0) {
 | 
			
		||||
			_mediaButtons[i]->setText(overviewLinkText(i, count));
 | 
			
		||||
			if (_mediaButtons[i]->isHidden()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -902,6 +902,12 @@ void MessageLink::onClick(Qt::MouseButton button) const {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CommentsLink::onClick(Qt::MouseButton button) const {
 | 
			
		||||
	if (button == Qt::LeftButton && App::main() && _item->history()->isChannel()) {
 | 
			
		||||
		App::main()->showPeerHistory(_item->history()->peer->id, _item->id);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MsgId clientMsgId() {
 | 
			
		||||
	static MsgId current = -2000000000;
 | 
			
		||||
	return ++current;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -127,6 +127,7 @@ inline bool operator<(const FullMsgId &a, const FullMsgId &b) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static const MsgId ShowAtTheEndMsgId = -0x40000000;
 | 
			
		||||
static const MsgId SwitchAtTopMsgId = -0x3FFFFFFF;
 | 
			
		||||
static const MsgId ShowAtUnreadMsgId = 0;
 | 
			
		||||
 | 
			
		||||
struct NotifySettings {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,8 @@ typedef quint32 uint32;
 | 
			
		|||
typedef qint64 int64;
 | 
			
		||||
typedef quint64 uint64;
 | 
			
		||||
 | 
			
		||||
static const int32 ScrollMax = INT_MAX;
 | 
			
		||||
 | 
			
		||||
#ifdef Q_OS_WIN
 | 
			
		||||
typedef float float32;
 | 
			
		||||
typedef double float64;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue