mirror of https://github.com/procxx/kepka.git
				
				
				
			Delete for everyone checkbox added. Various bugfixes.
This commit is contained in:
		
							parent
							
								
									218f991547
								
							
						
					
					
						commit
						eec5b78054
					
				|  | @ -959,6 +959,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org | |||
| "lng_selected_delete_sure_this" = "Do you want to delete this message?"; | ||||
| "lng_selected_delete_sure" = "Do you want to delete {count:_not_used_|# message|# messages}?"; | ||||
| "lng_delete_photo_sure" = "Do you want to delete this photo?"; | ||||
| "lng_delete_for_everyone_this_hint" = "This will delete it for everyone in this chat."; | ||||
| "lng_delete_for_everyone_hint" = "This will delete {count:_not_used_|it|them} for everyone in this chat."; | ||||
| "lng_delete_for_me_chat_this_hint" = "This will delete it just for you, not for other participants of the chat."; | ||||
| "lng_delete_for_me_chat_hint" = "This will delete {count:_not_used_|it|them} just for you, not for other participants of the chat."; | ||||
| "lng_delete_for_me_this_hint" = "This will delete it just for you."; | ||||
| "lng_delete_for_me_hint" = "This will delete {count:_not_used_|it|them} just for you."; | ||||
| "lng_delete_for_everyone_check" = "Delete for everyone"; | ||||
| "lng_delete_for_other_check" = "Delete for {user}"; | ||||
| "lng_box_delete" = "Delete"; | ||||
| "lng_box_leave" = "Leave"; | ||||
| 
 | ||||
|  |  | |||
|  | @ -33,6 +33,16 @@ defaultBoxButton: RoundButton(defaultLightButton) { | |||
| 	font: boxButtonFont; | ||||
| } | ||||
| 
 | ||||
| boxTextStyle: TextStyle(defaultTextStyle) { | ||||
| 	font: font(boxFontSize); | ||||
| 	linkFont: font(boxFontSize); | ||||
| 	linkFontOver: font(boxFontSize underline); | ||||
| } | ||||
| 
 | ||||
| boxLabelStyle: TextStyle(boxTextStyle) { | ||||
| 	lineHeight: 22px; | ||||
| } | ||||
| 
 | ||||
| attentionBoxButton: RoundButton(defaultBoxButton) { | ||||
| 	textFg: attentionButtonFg; | ||||
| 	textFgOver: attentionButtonFgOver; | ||||
|  | @ -46,7 +56,7 @@ attentionBoxButton: RoundButton(defaultBoxButton) { | |||
| defaultBoxCheckbox: Checkbox(defaultCheckbox) { | ||||
| 	width: -46px; | ||||
| 	textPosition: point(34px, 1px); | ||||
| 	font: boxTextFont; | ||||
| 	style: boxTextStyle; | ||||
| } | ||||
| 
 | ||||
| boxRoundShadow: Shadow { | ||||
|  | @ -108,12 +118,9 @@ boxMediumSkip: 20px; | |||
| boxButtonPadding: margins(8px, 12px, 13px, 12px); | ||||
| boxLayerButtonPadding: margins(8px, 8px, 8px, 8px); | ||||
| boxLabel: FlatLabel(defaultFlatLabel) { | ||||
| 	width: 285px; | ||||
| 	align: align(topleft); | ||||
| 	style: TextStyle(defaultTextStyle) { | ||||
| 		font: font(boxFontSize); | ||||
| 		linkFont: font(boxFontSize); | ||||
| 		linkFontOver: font(boxFontSize underline); | ||||
| 	} | ||||
| 	style: boxLabelStyle; | ||||
| } | ||||
| 
 | ||||
| countryRowHeight: 36px; | ||||
|  | @ -131,10 +138,6 @@ countriesScroll: ScrollArea(boxLayerScroll) { | |||
| 	deltab: 3px; | ||||
| } | ||||
| 
 | ||||
| boxTextStyle: TextStyle(defaultTextStyle) { | ||||
| 	lineHeight: 22px; | ||||
| } | ||||
| 
 | ||||
| boxPhotoTitleFont: font(16px semibold); | ||||
| boxPhotoTitlePosition: point(28px, 20px); | ||||
| boxPhotoPadding: margins(28px, 28px, 28px, 18px); | ||||
|  |  | |||
|  | @ -112,7 +112,7 @@ base::lambda<void()> ConfirmBox::generateInformCallback(const base::lambda_copy< | |||
| } | ||||
| 
 | ||||
| void ConfirmBox::init(const QString &text) { | ||||
| 	_text.setText(st::boxTextStyle, text, _informative ? _confirmBoxTextOptions : _textPlainOptions); | ||||
| 	_text.setText(st::boxLabelStyle, text, _informative ? _confirmBoxTextOptions : _textPlainOptions); | ||||
| } | ||||
| 
 | ||||
| void ConfirmBox::prepare() { | ||||
|  | @ -125,7 +125,7 @@ void ConfirmBox::prepare() { | |||
| 
 | ||||
| void ConfirmBox::textUpdated() { | ||||
| 	_textWidth = st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right(); | ||||
| 	_textHeight = qMin(_text.countHeight(_textWidth), 16 * int(st::boxTextStyle.lineHeight)); | ||||
| 	_textHeight = qMin(_text.countHeight(_textWidth), 16 * st::boxLabelStyle.lineHeight); | ||||
| 	setDimensions(st::boxWidth, st::boxPadding.top() + _textHeight + st::boxPadding.bottom()); | ||||
| 
 | ||||
| 	setMouseTracking(_text.hasLinks()); | ||||
|  | @ -219,7 +219,7 @@ InformBox::InformBox(QWidget*, const QString &text, const QString &doneText, bas | |||
| } | ||||
| 
 | ||||
| MaxInviteBox::MaxInviteBox(QWidget*, const QString &link) | ||||
| : _text(st::boxTextStyle, lng_participant_invite_sorry(lt_count, Global::ChatSizeMax()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) | ||||
| : _text(st::boxLabelStyle, lng_participant_invite_sorry(lt_count, Global::ChatSizeMax()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) | ||||
| , _link(link) { | ||||
| } | ||||
| 
 | ||||
|  | @ -229,7 +229,7 @@ void MaxInviteBox::prepare() { | |||
| 	addButton(lang(lng_box_ok), [this] { closeBox(); }); | ||||
| 
 | ||||
| 	_textWidth = st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right(); | ||||
| 	_textHeight = qMin(_text.countHeight(_textWidth), 16 * int(st::boxTextStyle.lineHeight)); | ||||
| 	_textHeight = qMin(_text.countHeight(_textWidth), 16 * st::boxLabelStyle.lineHeight); | ||||
| 	setDimensions(st::boxWidth, st::boxPadding.top() + _textHeight + st::boxTextFont->height + st::boxTextFont->height * 2 + st::newGroupLinkPadding.bottom()); | ||||
| } | ||||
| 
 | ||||
|  | @ -302,8 +302,8 @@ void ConvertToSupergroupBox::prepare() { | |||
| 	addButton(lang(lng_profile_convert_confirm), [this] { convertToSupergroup(); }); | ||||
| 	addButton(lang(lng_cancel), [this] { closeBox(); }); | ||||
| 
 | ||||
| 	_text.setText(st::boxTextStyle, text.join('\n'), _confirmBoxTextOptions); | ||||
| 	_note.setText(st::boxTextStyle, lng_profile_convert_warning(lt_bold_start, textcmdStartSemibold(), lt_bold_end, textcmdStopSemibold()), _confirmBoxTextOptions); | ||||
| 	_text.setText(st::boxLabelStyle, text.join('\n'), _confirmBoxTextOptions); | ||||
| 	_note.setText(st::boxLabelStyle, lng_profile_convert_warning(lt_bold_start, textcmdStartSemibold(), lt_bold_end, textcmdStopSemibold()), _confirmBoxTextOptions); | ||||
| 	_textWidth = st::boxWideWidth - st::boxPadding.left() - st::boxButtonPadding.right(); | ||||
| 	_textHeight = _text.countHeight(_textWidth); | ||||
| 	setDimensions(st::boxWideWidth, _textHeight + st::boxPadding.bottom() + _note.countHeight(_textWidth)); | ||||
|  | @ -408,54 +408,135 @@ bool PinMessageBox::pinFail(const RPCError &error) { | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| RichDeleteMessageBox::RichDeleteMessageBox(QWidget*, ChannelData *channel, UserData *from, MsgId msgId) | ||||
| : _channel(channel) | ||||
| , _from(from) | ||||
| , _msgId(msgId) | ||||
| , _text(this, lang(lng_selected_delete_sure_this), Ui::FlatLabel::InitType::Simple, st::boxLabel) | ||||
| , _banUser(this, lang(lng_ban_user), false, st::defaultBoxCheckbox) | ||||
| , _reportSpam(this, lang(lng_report_spam), false, st::defaultBoxCheckbox) | ||||
| , _deleteAll(this, lang(lng_delete_all_from), false, st::defaultBoxCheckbox) { | ||||
| DeleteMessagesBox::DeleteMessagesBox(QWidget*, HistoryItem *item, bool suggestModerateActions) : _singleItem(true) { | ||||
| 	_ids.push_back(item->fullId()); | ||||
| 	if (suggestModerateActions && item->suggestBanReportDeleteAll()) { | ||||
| 		_moderateFrom = item->from()->asUser(); | ||||
| 		_moderateInChannel = item->history()->peer->asChannel(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void RichDeleteMessageBox::prepare() { | ||||
| 	t_assert(_channel != nullptr); | ||||
| DeleteMessagesBox::DeleteMessagesBox(QWidget*, const SelectedItemSet &selected) { | ||||
| 	auto count = selected.size(); | ||||
| 	t_assert(count > 0); | ||||
| 	_ids.reserve(count); | ||||
| 	for_const (auto item, selected) { | ||||
| 		_ids.push_back(item->fullId()); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void DeleteMessagesBox::prepare() { | ||||
| 	auto text = QString(); | ||||
| 	if (_moderateFrom) { | ||||
| 		t_assert(_moderateInChannel != nullptr); | ||||
| 		text = lang(lng_selected_delete_sure_this); | ||||
| 		_banUser.create(this, lang(lng_ban_user), false, st::defaultBoxCheckbox); | ||||
| 		_reportSpam.create(this, lang(lng_report_spam), false, st::defaultBoxCheckbox); | ||||
| 		_deleteAll.create(this, lang(lng_delete_all_from), false, st::defaultBoxCheckbox); | ||||
| 	} else { | ||||
| 		text = _singleItem ? lang(lng_selected_delete_sure_this) : lng_selected_delete_sure(lt_count, _ids.size()); | ||||
| 		auto canDeleteAllForEveryone = true; | ||||
| 		auto now = ::date(unixtime()); | ||||
| 		auto deleteForUser = (UserData*)nullptr; | ||||
| 		auto peer = (PeerData*)nullptr; | ||||
| 		auto forEveryoneText = lang(lng_delete_for_everyone_check); | ||||
| 		for_const (auto fullId, _ids) { | ||||
| 			if (auto item = App::histItemById(fullId)) { | ||||
| 				peer = item->history()->peer; | ||||
| 				if (!item->canDeleteForEveryone(now)) { | ||||
| 					canDeleteAllForEveryone = false; | ||||
| 					break; | ||||
| 				} else if (auto user = item->history()->peer->asUser()) { | ||||
| 					if (!deleteForUser || deleteForUser == user) { | ||||
| 						deleteForUser = user; | ||||
| 						forEveryoneText = lng_delete_for_other_check(lt_user, user->firstName); | ||||
| 					} else { | ||||
| 						forEveryoneText = lang(lng_delete_for_everyone_check); | ||||
| 					} | ||||
| 				} | ||||
| 			} else { | ||||
| 				canDeleteAllForEveryone = false; | ||||
| 			} | ||||
| 		} | ||||
| 		if (canDeleteAllForEveryone) { | ||||
| 			_forEveryone.create(this, forEveryoneText, false, st::defaultBoxCheckbox); | ||||
| 		} else if (peer && peer->isChannel()) { | ||||
| 			if (peer->isMegagroup()) { | ||||
| 				text += qsl("\n\n") + (_singleItem ? lang(lng_delete_for_everyone_this_hint) : lng_delete_for_everyone_hint(lt_count, _ids.size())); | ||||
| 			} | ||||
| 		} else if (peer->isChat()) { | ||||
| 			text += qsl("\n\n") + (_singleItem ? lang(lng_delete_for_me_chat_this_hint) : lng_delete_for_me_chat_hint(lt_count, _ids.size())); | ||||
| 		} else { | ||||
| 			text += qsl("\n\n") + (_singleItem ? lang(lng_delete_for_me_this_hint) : lng_delete_for_me_hint(lt_count, _ids.size())); | ||||
| 		} | ||||
| 	} | ||||
| 	_text.create(this, text, Ui::FlatLabel::InitType::Simple, st::boxLabel); | ||||
| 
 | ||||
| 	addButton(lang(lng_box_delete), [this] { deleteAndClear(); }); | ||||
| 	addButton(lang(lng_cancel), [this] { closeBox(); }); | ||||
| 
 | ||||
| 	_text->resizeToWidth(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()); | ||||
| 	setDimensions(st::boxWidth, st::boxPadding.top() + _text->height() + st::boxMediumSkip + _banUser->heightNoMargins() + st::boxLittleSkip + _reportSpam->heightNoMargins() + st::boxLittleSkip + _deleteAll->heightNoMargins() + st::boxPadding.bottom()); | ||||
| 	auto fullHeight = st::boxPadding.top() + _text->height() + st::boxPadding.bottom(); | ||||
| 	if (_moderateFrom) { | ||||
| 		fullHeight += st::boxMediumSkip + _banUser->heightNoMargins() + st::boxLittleSkip + _reportSpam->heightNoMargins() + st::boxLittleSkip + _deleteAll->heightNoMargins(); | ||||
| 	} else if (_forEveryone) { | ||||
| 		fullHeight += st::boxMediumSkip + _forEveryone->heightNoMargins(); | ||||
| 	} | ||||
| 	setDimensions(st::boxWidth, fullHeight); | ||||
| } | ||||
| 
 | ||||
| void RichDeleteMessageBox::resizeEvent(QResizeEvent *e) { | ||||
| void DeleteMessagesBox::resizeEvent(QResizeEvent *e) { | ||||
| 	BoxContent::resizeEvent(e); | ||||
| 	_text->moveToLeft(st::boxPadding.left(), st::boxPadding.top()); | ||||
| 	_banUser->moveToLeft(st::boxPadding.left(), _text->bottomNoMargins() + st::boxMediumSkip); | ||||
| 	_reportSpam->moveToLeft(st::boxPadding.left(), _banUser->bottomNoMargins() + st::boxLittleSkip); | ||||
| 	_deleteAll->moveToLeft(st::boxPadding.left(), _reportSpam->bottomNoMargins() + st::boxLittleSkip); | ||||
| 	if (_moderateFrom) { | ||||
| 		_banUser->moveToLeft(st::boxPadding.left(), _text->bottomNoMargins() + st::boxMediumSkip); | ||||
| 		_reportSpam->moveToLeft(st::boxPadding.left(), _banUser->bottomNoMargins() + st::boxLittleSkip); | ||||
| 		_deleteAll->moveToLeft(st::boxPadding.left(), _reportSpam->bottomNoMargins() + st::boxLittleSkip); | ||||
| 	} else if (_forEveryone) { | ||||
| 		_forEveryone->moveToLeft(st::boxPadding.left(), _text->bottomNoMargins() + st::boxMediumSkip); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void RichDeleteMessageBox::deleteAndClear() { | ||||
| 	if (_banUser->checked()) { | ||||
| 		MTP::send(MTPchannels_KickFromChannel(_channel->inputChannel, _from->inputUser, MTP_boolTrue()), App::main()->rpcDone(&MainWidget::sentUpdatesReceived)); | ||||
| void DeleteMessagesBox::deleteAndClear() { | ||||
| 	if (!App::main()) { | ||||
| 		return; | ||||
| 	} | ||||
| 	if (_reportSpam->checked()) { | ||||
| 		MTP::send(MTPchannels_ReportSpam(_channel->inputChannel, _from->inputUser, MTP_vector<MTPint>(1, MTP_int(_msgId)))); | ||||
| 	} | ||||
| 	if (_deleteAll->checked()) { | ||||
| 		App::main()->deleteAllFromUser(_channel, _from); | ||||
| 	} | ||||
| 	if (auto item = App::histItemById(_channel ? peerToChannel(_channel->id) : 0, _msgId)) { | ||||
| 		auto wasLast = (item->history()->lastMsg == item); | ||||
| 		item->destroy(); | ||||
| 
 | ||||
| 		if (_msgId > 0) { | ||||
| 			auto forEveryone = true; | ||||
| 			App::main()->deleteMessages(_channel, QVector<MTPint>(1, MTP_int(_msgId)), forEveryone); | ||||
| 		} else if (wasLast) { | ||||
| 			App::main()->checkPeerHistory(_channel); | ||||
| 	if (_moderateFrom) { | ||||
| 		if (_banUser->checked()) { | ||||
| 			MTP::send(MTPchannels_KickFromChannel(_moderateInChannel->inputChannel, _moderateFrom->inputUser, MTP_boolTrue()), App::main()->rpcDone(&MainWidget::sentUpdatesReceived)); | ||||
| 		} | ||||
| 		if (_reportSpam->checked()) { | ||||
| 			MTP::send(MTPchannels_ReportSpam(_moderateInChannel->inputChannel, _moderateFrom->inputUser, MTP_vector<MTPint>(1, MTP_int(_ids[0].msg)))); | ||||
| 		} | ||||
| 		if (_deleteAll->checked()) { | ||||
| 			App::main()->deleteAllFromUser(_moderateInChannel, _moderateFrom); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!_singleItem) { | ||||
| 		App::main()->clearSelectedItems(); | ||||
| 	} | ||||
| 
 | ||||
| 	QMap<PeerData*, QVector<MTPint>> idsByPeer; | ||||
| 	for_const (auto fullId, _ids) { | ||||
| 		if (auto item = App::histItemById(fullId)) { | ||||
| 			auto history = item->history(); | ||||
| 			auto wasOnServer = (item->id > 0); | ||||
| 			auto wasLast = (history->lastMsg == item); | ||||
| 			item->destroy(); | ||||
| 
 | ||||
| 			if (wasOnServer) { | ||||
| 				idsByPeer[history->peer].push_back(MTP_int(fullId.msg)); | ||||
| 			} else if (wasLast) { | ||||
| 				App::main()->checkPeerHistory(history->peer); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	auto forEveryone = _forEveryone ? _forEveryone->checked() : false; | ||||
| 	for (auto i = idsByPeer.cbegin(), e = idsByPeer.cend(); i != e; ++i) { | ||||
| 		App::main()->deleteMessages(i.key(), i.value(), forEveryone); | ||||
| 	} | ||||
| 	Ui::hideLayer(); | ||||
| } | ||||
|  |  | |||
|  | @ -170,9 +170,10 @@ private: | |||
| 
 | ||||
| }; | ||||
| 
 | ||||
| class RichDeleteMessageBox : public BoxContent, public RPCSender { | ||||
| class DeleteMessagesBox : public BoxContent, public RPCSender { | ||||
| public: | ||||
| 	RichDeleteMessageBox(QWidget*, ChannelData *channel, UserData *from, MsgId msgId); | ||||
| 	DeleteMessagesBox(QWidget*, HistoryItem *item, bool suggestModerateActions); | ||||
| 	DeleteMessagesBox(QWidget*, const SelectedItemSet &selected); | ||||
| 
 | ||||
| protected: | ||||
| 	void prepare() override; | ||||
|  | @ -182,14 +183,16 @@ protected: | |||
| private: | ||||
| 	void deleteAndClear(); | ||||
| 
 | ||||
| 	ChannelData *_channel; | ||||
| 	UserData *_from; | ||||
| 	MsgId _msgId; | ||||
| 	QVector<FullMsgId> _ids; | ||||
| 	bool _singleItem = false; | ||||
| 	UserData *_moderateFrom = nullptr; | ||||
| 	ChannelData *_moderateInChannel = nullptr; | ||||
| 
 | ||||
| 	object_ptr<Ui::FlatLabel> _text; | ||||
| 	object_ptr<Ui::Checkbox> _banUser; | ||||
| 	object_ptr<Ui::Checkbox> _reportSpam; | ||||
| 	object_ptr<Ui::Checkbox> _deleteAll; | ||||
| 	object_ptr<Ui::FlatLabel> _text = { nullptr }; | ||||
| 	object_ptr<Ui::Checkbox> _forEveryone = { nullptr }; | ||||
| 	object_ptr<Ui::Checkbox> _banUser = { nullptr }; | ||||
| 	object_ptr<Ui::Checkbox> _reportSpam = { nullptr }; | ||||
| 	object_ptr<Ui::Checkbox> _deleteAll = { nullptr }; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -374,7 +374,7 @@ void MembersBox::Inner::refresh() { | |||
| 		resize(width(), st::membersMarginTop + st::noContactsHeight + st::membersMarginBottom); | ||||
| 		_aboutHeight = 0; | ||||
| 	} else { | ||||
| 		_about.setText(st::boxTextStyle, lng_channel_only_last_shown(lt_count, _rows.size())); | ||||
| 		_about.setText(st::boxLabelStyle, lng_channel_only_last_shown(lt_count, _rows.size())); | ||||
| 		_aboutHeight = st::membersAboutLimitPadding.top() + _about.countHeight(_aboutWidth) + st::membersAboutLimitPadding.bottom(); | ||||
| 		if (_filter != MembersFilter::Recent || (_rows.size() >= _channel->membersCount() && _rows.size() < Global::ChatSizeMax())) { | ||||
| 			_aboutHeight = 0; | ||||
|  |  | |||
|  | @ -148,7 +148,7 @@ StickersBox::StickersBox(QWidget*, const Stickers::Order &archivedIds) | |||
| : _section(Section::ArchivedPart) | ||||
| , _archived(0, this, archivedIds) | ||||
| , _aboutWidth(st::boxWideWidth - 2 * st::stickersReorderPadding.top()) | ||||
| , _about(st::boxTextStyle, lang(lng_stickers_packs_archived), _defaultOptions, _aboutWidth) { | ||||
| , _about(st::boxLabelStyle, lang(lng_stickers_packs_archived), _defaultOptions, _aboutWidth) { | ||||
| } | ||||
| 
 | ||||
| void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result) { | ||||
|  |  | |||
|  | @ -316,18 +316,7 @@ PeerData *getPeerForMouseAction() { | |||
| bool hideWindowNoQuit() { | ||||
| 	if (!App::quitting()) { | ||||
| 		if (auto w = App::wnd()) { | ||||
| 			if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { | ||||
| 				if (w->minimizeToTray()) { | ||||
| 					Ui::showChatsList(); | ||||
| 					return true; | ||||
| 				} | ||||
| 			} else if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { | ||||
| 				w->closeWithoutDestroy(); | ||||
| 				w->updateIsActive(Global::OfflineBlurTimeout()); | ||||
| 				w->updateGlobalMenu(); | ||||
| 				Ui::showChatsList(); | ||||
| 				return true; | ||||
| 			} | ||||
| 			w->hideNoQuit(); | ||||
| 		} | ||||
| 	} | ||||
| 	return false; | ||||
|  |  | |||
|  | @ -48,6 +48,14 @@ constexpr int kSetMyActionForMs = 10000; | |||
| 
 | ||||
| auto GlobalPinnedIndex = 0; | ||||
| 
 | ||||
| HistoryItem *createUnsupportedMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from) { | ||||
| 	QString text(lng_message_unsupported(lt_link, qsl("https://desktop.telegram.org"))); | ||||
| 	EntitiesInText entities; | ||||
| 	textParseEntities(text, _historyTextNoMonoOptions.flags, &entities); | ||||
| 	entities.push_front(EntityInText(EntityInTextItalic, 0, text.size())); | ||||
| 	return HistoryMessage::create(history, msgId, flags, replyTo, viaBotId, date, from, { text, entities }); | ||||
| } | ||||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| void historyInit() { | ||||
|  | @ -741,7 +749,7 @@ void Histories::clearPinned() { | |||
| } | ||||
| 
 | ||||
| HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem) { | ||||
| 	MsgId msgId = 0; | ||||
| 	auto msgId = MsgId(0); | ||||
| 	switch (msg.type()) { | ||||
| 	case mtpc_messageEmpty: msgId = msg.c_messageEmpty().vid.v; break; | ||||
| 	case mtpc_message: msgId = msg.c_message().vid.v; break; | ||||
|  | @ -749,7 +757,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, | |||
| 	} | ||||
| 	if (!msgId) return nullptr; | ||||
| 
 | ||||
| 	HistoryItem *result = App::histItemById(channelId(), msgId); | ||||
| 	auto result = App::histItemById(channelId(), msgId); | ||||
| 	if (result) { | ||||
| 		if (!result->detached() && detachExistingItem) { | ||||
| 			result->detach(); | ||||
|  | @ -769,37 +777,42 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, | |||
| 	break; | ||||
| 
 | ||||
| 	case mtpc_message: { | ||||
| 		const auto &m(msg.c_message()); | ||||
| 		int badMedia = 0; // 1 - unsupported, 2 - empty
 | ||||
| 		auto &m = msg.c_message(); | ||||
| 		enum class MediaCheckResult { | ||||
| 			Good, | ||||
| 			Unsupported, | ||||
| 			Empty, | ||||
| 		}; | ||||
| 		auto badMedia = MediaCheckResult::Good; | ||||
| 		if (m.has_media()) switch (m.vmedia.type()) { | ||||
| 		case mtpc_messageMediaEmpty: | ||||
| 		case mtpc_messageMediaContact: break; | ||||
| 		case mtpc_messageMediaGeo: | ||||
| 			switch (m.vmedia.c_messageMediaGeo().vgeo.type()) { | ||||
| 			case mtpc_geoPoint: break; | ||||
| 			case mtpc_geoPointEmpty: badMedia = 2; break; | ||||
| 			default: badMedia = 1; break; | ||||
| 			case mtpc_geoPointEmpty: badMedia = MediaCheckResult::Empty; break; | ||||
| 			default: badMedia = MediaCheckResult::Unsupported; break; | ||||
| 			} | ||||
| 			break; | ||||
| 		case mtpc_messageMediaVenue: | ||||
| 			switch (m.vmedia.c_messageMediaVenue().vgeo.type()) { | ||||
| 			case mtpc_geoPoint: break; | ||||
| 			case mtpc_geoPointEmpty: badMedia = 2; break; | ||||
| 			default: badMedia = 1; break; | ||||
| 			case mtpc_geoPointEmpty: badMedia = MediaCheckResult::Empty; break; | ||||
| 			default: badMedia = MediaCheckResult::Unsupported; break; | ||||
| 			} | ||||
| 			break; | ||||
| 		case mtpc_messageMediaPhoto: | ||||
| 			switch (m.vmedia.c_messageMediaPhoto().vphoto.type()) { | ||||
| 			case mtpc_photo: break; | ||||
| 			case mtpc_photoEmpty: badMedia = 2; break; | ||||
| 			default: badMedia = 1; break; | ||||
| 			case mtpc_photoEmpty: badMedia = MediaCheckResult::Empty; break; | ||||
| 			default: badMedia = MediaCheckResult::Unsupported; break; | ||||
| 			} | ||||
| 			break; | ||||
| 		case mtpc_messageMediaDocument: | ||||
| 			switch (m.vmedia.c_messageMediaDocument().vdocument.type()) { | ||||
| 			case mtpc_document: break; | ||||
| 			case mtpc_documentEmpty: badMedia = 2; break; | ||||
| 			default: badMedia = 1; break; | ||||
| 			case mtpc_documentEmpty: badMedia = MediaCheckResult::Empty; break; | ||||
| 			default: badMedia = MediaCheckResult::Unsupported; break; | ||||
| 			} | ||||
| 			break; | ||||
| 		case mtpc_messageMediaWebPage: | ||||
|  | @ -808,25 +821,21 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, | |||
| 			case mtpc_webPageEmpty: | ||||
| 			case mtpc_webPagePending: break; | ||||
| 			case mtpc_webPageNotModified: | ||||
| 			default: badMedia = 1; break; | ||||
| 			default: badMedia = MediaCheckResult::Unsupported; break; | ||||
| 			} | ||||
| 			break; | ||||
| 		case mtpc_messageMediaGame: | ||||
| 		switch (m.vmedia.c_messageMediaGame().vgame.type()) { | ||||
| 			case mtpc_game: break; | ||||
| 			default: badMedia = 1; break; | ||||
| 			default: badMedia = MediaCheckResult::Unsupported; break; | ||||
| 			} | ||||
| 			break; | ||||
| 		case mtpc_messageMediaUnsupported: | ||||
| 		default: badMedia = 1; break; | ||||
| 		default: badMedia = MediaCheckResult::Unsupported; break; | ||||
| 		} | ||||
| 		if (badMedia == 1) { | ||||
| 			QString text(lng_message_unsupported(lt_link, qsl("https://desktop.telegram.org"))); | ||||
| 			EntitiesInText entities; | ||||
| 			textParseEntities(text, _historyTextNoMonoOptions.flags, &entities); | ||||
| 			entities.push_front(EntityInText(EntityInTextItalic, 0, text.size())); | ||||
| 			result = HistoryMessage::create(this, m.vid.v, m.vflags.v, m.vreply_to_msg_id.v, m.vvia_bot_id.v, date(m.vdate), m.vfrom_id.v, { text, entities }); | ||||
| 		} else if (badMedia) { | ||||
| 		if (badMedia == MediaCheckResult::Unsupported) { | ||||
| 			result = createUnsupportedMessage(this, m.vid.v, m.vflags.v, m.vreply_to_msg_id.v, m.vvia_bot_id.v, date(m.vdate), m.vfrom_id.v); | ||||
| 		} else if (badMedia == MediaCheckResult::Empty) { | ||||
| 			result = HistoryService::create(this, m.vid.v, date(m.vdate), lang(lng_message_empty), m.vflags.v, m.has_from_id() ? m.vfrom_id.v : 0); | ||||
| 		} else { | ||||
| 			result = HistoryMessage::create(this, m); | ||||
|  | @ -834,18 +843,23 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, | |||
| 	} break; | ||||
| 
 | ||||
| 	case mtpc_messageService: { | ||||
| 		const auto &d(msg.c_messageService()); | ||||
| 		result = HistoryService::create(this, d); | ||||
| 		auto &m = msg.c_messageService(); | ||||
| 		if (m.vaction.type() == mtpc_messageActionPhoneCall) { | ||||
| 			auto viaBotId = 0; | ||||
| 			result = createUnsupportedMessage(this, m.vid.v, mtpCastFlags(m.vflags.v), m.vreply_to_msg_id.v, viaBotId, date(m.vdate), m.vfrom_id.v); | ||||
| 		} else { | ||||
| 			result = HistoryService::create(this, m); | ||||
| 		} | ||||
| 
 | ||||
| 		if (applyServiceAction) { | ||||
| 			const auto &action(d.vaction); | ||||
| 			switch (d.vaction.type()) { | ||||
| 			auto &action = m.vaction; | ||||
| 			switch (action.type()) { | ||||
| 			case mtpc_messageActionChatAddUser: { | ||||
| 				const auto &d(action.c_messageActionChatAddUser()); | ||||
| 				auto &d = action.c_messageActionChatAddUser(); | ||||
| 				if (peer->isMegagroup()) { | ||||
| 					const auto &v(d.vusers.c_vector().v); | ||||
| 					for (int32 i = 0, l = v.size(); i < l; ++i) { | ||||
| 						if (UserData *user = App::userLoaded(peerFromUser(v.at(i)))) { | ||||
| 					auto &v = d.vusers.c_vector().v; | ||||
| 					for (auto i = 0, l = v.size(); i != l; ++i) { | ||||
| 						if (auto user = App::userLoaded(peerFromUser(v[i]))) { | ||||
| 							if (peer->asChannel()->mgInfo->lastParticipants.indexOf(user) < 0) { | ||||
| 								peer->asChannel()->mgInfo->lastParticipants.push_front(user); | ||||
| 								peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated; | ||||
|  | @ -863,7 +877,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, | |||
| 			} break; | ||||
| 
 | ||||
| 			case mtpc_messageActionChatJoinedByLink: { | ||||
| 				const auto &d(action.c_messageActionChatJoinedByLink()); | ||||
| 				auto &d = action.c_messageActionChatJoinedByLink(); | ||||
| 				if (peer->isMegagroup()) { | ||||
| 					if (result->from()->isUser()) { | ||||
| 						if (peer->asChannel()->mgInfo->lastParticipants.indexOf(result->from()->asUser()) < 0) { | ||||
|  | @ -881,13 +895,13 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, | |||
| 			} break; | ||||
| 
 | ||||
| 			case mtpc_messageActionChatDeletePhoto: { | ||||
| 				ChatData *chat = peer->asChat(); | ||||
| 				auto chat = peer->asChat(); | ||||
| 				if (chat) chat->setPhoto(MTP_chatPhotoEmpty()); | ||||
| 			} break; | ||||
| 
 | ||||
| 			case mtpc_messageActionChatDeleteUser: { | ||||
| 				const auto &d(action.c_messageActionChatDeleteUser()); | ||||
| 				PeerId uid = peerFromUser(d.vuser_id); | ||||
| 				auto &d = action.c_messageActionChatDeleteUser(); | ||||
| 				auto uid = peerFromUser(d.vuser_id); | ||||
| 				if (lastKeyboardFrom == uid) { | ||||
| 					clearLastKeyboard(); | ||||
| 				} | ||||
|  | @ -952,7 +966,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, | |||
| 			} break; | ||||
| 
 | ||||
| 			case mtpc_messageActionChatEditTitle: { | ||||
| 				auto &d(action.c_messageActionChatEditTitle()); | ||||
| 				auto &d = action.c_messageActionChatEditTitle(); | ||||
| 				if (auto chat = peer->asChat()) { | ||||
| 					chat->setName(qs(d.vtitle)); | ||||
| 				} | ||||
|  | @ -961,18 +975,18 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, | |||
| 			case mtpc_messageActionChatMigrateTo: { | ||||
| 				peer->asChat()->flags |= MTPDchat::Flag::f_deactivated; | ||||
| 
 | ||||
| 				//const auto &d(action.c_messageActionChatMigrateTo());
 | ||||
| 				//PeerData *channel = App::channelLoaded(d.vchannel_id.v);
 | ||||
| 				//auto &d = action.c_messageActionChatMigrateTo();
 | ||||
| 				//auto channel = App::channelLoaded(d.vchannel_id.v);
 | ||||
| 			} break; | ||||
| 
 | ||||
| 			case mtpc_messageActionChannelMigrateFrom: { | ||||
| 				//const auto &d(action.c_messageActionChannelMigrateFrom());
 | ||||
| 				//PeerData *chat = App::chatLoaded(d.vchat_id.v);
 | ||||
| 				//auto &d = action.c_messageActionChannelMigrateFrom();
 | ||||
| 				//auto chat = App::chatLoaded(d.vchat_id.v);
 | ||||
| 			} break; | ||||
| 
 | ||||
| 			case mtpc_messageActionPinMessage: { | ||||
| 				if (d.has_reply_to_msg_id() && result && result->history()->peer->isMegagroup()) { | ||||
| 					result->history()->peer->asChannel()->mgInfo->pinnedMsgId = d.vreply_to_msg_id.v; | ||||
| 				if (m.has_reply_to_msg_id() && result && result->history()->peer->isMegagroup()) { | ||||
| 					result->history()->peer->asChannel()->mgInfo->pinnedMsgId = m.vreply_to_msg_id.v; | ||||
| 					if (App::main()) emit App::main()->peerUpdated(result->history()->peer); | ||||
| 				} | ||||
| 			} break; | ||||
|  |  | |||
|  | @ -772,6 +772,18 @@ bool HistoryItem::canEdit(const QDateTime &cur) const { | |||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool HistoryItem::canDeleteForEveryone(const QDateTime &cur) const { | ||||
| 	auto messageToMyself = (peerToUser(_history->peer->id) == MTP::authedId()); | ||||
| 	auto messageTooOld = messageToMyself ? false : (date.secsTo(cur) >= Global::EditTimeLimit()); | ||||
| 	if (id < 0 || messageToMyself || messageTooOld) return false; | ||||
| 	if (history()->peer->isChannel()) return false; | ||||
| 
 | ||||
| 	if (auto msg = toHistoryMessage()) { | ||||
| 		return !isPost() && out(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool HistoryItem::unread() const { | ||||
| 	// Messages from myself are always read.
 | ||||
| 	if (history()->peer->isSelf()) return false; | ||||
|  |  | |||
|  | @ -704,6 +704,7 @@ public: | |||
| 	} | ||||
| 
 | ||||
| 	bool canEdit(const QDateTime &cur) const; | ||||
| 	bool canDeleteForEveryone(const QDateTime &cur) const; | ||||
| 
 | ||||
| 	bool suggestBanReportDeleteAll() const { | ||||
| 		ChannelData *channel = history()->peer->asChannel(); | ||||
|  |  | |||
|  | @ -2848,7 +2848,7 @@ void HistoryHider::resizeEvent(QResizeEvent *e) { | |||
| 			_send->show(); | ||||
| 			_cancel->show(); | ||||
| 		} | ||||
| 		h += st::boxTopMargin + qMax(st::boxTextFont->height, st::boxTextStyle.lineHeight) + st::boxButtonPadding.top() + _send->height() + st::boxButtonPadding.bottom(); | ||||
| 		h += st::boxTopMargin + qMax(st::boxTextFont->height, st::boxLabelStyle.lineHeight) + st::boxButtonPadding.top() + _send->height() + st::boxButtonPadding.bottom(); | ||||
| 	} else { | ||||
| 		h += st::historyForwardChooseFont->height; | ||||
| 		_send->hide(); | ||||
|  | @ -2862,7 +2862,7 @@ void HistoryHider::resizeEvent(QResizeEvent *e) { | |||
| bool HistoryHider::offerPeer(PeerId peer) { | ||||
| 	if (!peer) { | ||||
| 		_offered = nullptr; | ||||
| 		_toText.setText(st::boxTextStyle, QString()); | ||||
| 		_toText.setText(st::boxLabelStyle, QString()); | ||||
| 		_toTextWidth = 0; | ||||
| 		resizeEvent(nullptr); | ||||
| 		return false; | ||||
|  | @ -2902,7 +2902,7 @@ bool HistoryHider::offerPeer(PeerId peer) { | |||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	_toText.setText(st::boxTextStyle, phrase, _textNameOptions); | ||||
| 	_toText.setText(st::boxLabelStyle, phrase, _textNameOptions); | ||||
| 	_toTextWidth = _toText.maxWidth(); | ||||
| 	if (_toTextWidth > _box.width() - st::boxPadding.left() - st::boxLayerButtonPadding.right()) { | ||||
| 		_toTextWidth = _box.width() - st::boxPadding.left() - st::boxLayerButtonPadding.right(); | ||||
|  | @ -8352,8 +8352,13 @@ void HistoryWidget::confirmDeleteContextItem() { | |||
| 	auto item = App::contextItem(); | ||||
| 	if (!item || item->type() != HistoryItemMsg) return; | ||||
| 
 | ||||
| 	auto message = item->toHistoryMessage(); | ||||
| 	App::main()->deleteLayer((message && message->uploading()) ? -2 : -1); | ||||
| 	if (auto message = item->toHistoryMessage()) { | ||||
| 		if (message->uploading()) { | ||||
| 			App::main()->cancelUploadLayer(); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 	App::main()->deleteLayer(); | ||||
| } | ||||
| 
 | ||||
| void HistoryWidget::confirmDeleteSelectedItems() { | ||||
|  |  | |||
|  | @ -660,43 +660,39 @@ void MainWidget::forwardLayer(int forwardSelected) { | |||
| } | ||||
| 
 | ||||
| void MainWidget::deleteLayer(int selectedCount) { | ||||
| 	if (selectedCount == -1 && !_overview) { | ||||
| 		if (auto item = App::contextItem()) { | ||||
| 			if (item->suggestBanReportDeleteAll()) { | ||||
| 				Ui::show(Box<RichDeleteMessageBox>(item->history()->peer->asChannel(), item->from()->asUser(), item->id)); | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	auto text = (selectedCount < 0) ? lang(selectedCount < -1 ? lng_selected_cancel_sure_this : lng_selected_delete_sure_this) : lng_selected_delete_sure(lt_count, selectedCount); | ||||
| 	auto confirmText = lang((selectedCount < -1) ? lng_selected_upload_stop : lng_box_delete); | ||||
| 	auto cancelText = lang((selectedCount < -1) ? lng_continue : lng_cancel); | ||||
| 	if (selectedCount < -1) { | ||||
| 		if (auto item = App::contextItem()) { | ||||
| 			App::uploader()->pause(item->fullId()); | ||||
| 		} | ||||
| 	} | ||||
| 	Ui::show(Box<ConfirmBox>(text, confirmText, cancelText, base::lambda_guarded(this, [this, selectedCount] { | ||||
| 		if (selectedCount < 0) { | ||||
| 			if (_overview) { | ||||
| 				_overview->deleteContextItem(false); | ||||
| 			} else { | ||||
| 				_history->deleteContextItem(false); | ||||
| 			} | ||||
| 			if (selectedCount < -1) { | ||||
| 				App::uploader()->unpause(); | ||||
| 			} | ||||
| 	if (selectedCount) { | ||||
| 		auto forDelete = true; | ||||
| 		SelectedItemSet selected; | ||||
| 		if (_overview) { | ||||
| 			_overview->fillSelectedItems(selected, forDelete); | ||||
| 		} else { | ||||
| 			if (_overview) { | ||||
| 				_overview->deleteSelectedItems(false); | ||||
| 			} else { | ||||
| 				_history->deleteSelectedItems(false); | ||||
| 			} | ||||
| 			_history->fillSelectedItems(selected, forDelete); | ||||
| 		} | ||||
| 	}), base::lambda_guarded(this, [selectedCount] { | ||||
| 		if (selectedCount < -1) { | ||||
| 			App::uploader()->unpause(); | ||||
| 		if (!selected.isEmpty()) { | ||||
| 			Ui::show(Box<DeleteMessagesBox>(selected)); | ||||
| 		} | ||||
| 	} else if (auto item = App::contextItem()) { | ||||
| 		auto suggestModerateActions = !_overview; | ||||
| 		Ui::show(Box<DeleteMessagesBox>(item, suggestModerateActions)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void MainWidget::cancelUploadLayer() { | ||||
| 	auto item = App::contextItem(); | ||||
| 	if (!item) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	App::uploader()->pause(item->fullId()); | ||||
| 	Ui::show(Box<ConfirmBox>(lang(lng_selected_cancel_sure_this), lang(lng_selected_upload_stop), lang(lng_continue), base::lambda_guarded(this, [this] { | ||||
| 		if (_overview) { | ||||
| 			_overview->deleteContextItem(false); | ||||
| 		} else { | ||||
| 			_history->deleteContextItem(false); | ||||
| 		} | ||||
| 		App::uploader()->unpause(); | ||||
| 	}), base::lambda_guarded(this, [] { | ||||
| 		App::uploader()->unpause(); | ||||
| 	}))); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -228,7 +228,8 @@ public: | |||
| 	int32 dlgsWidth() const; | ||||
| 
 | ||||
| 	void forwardLayer(int forwardSelected = 0); // -1 - send paths
 | ||||
| 	void deleteLayer(int selectedCount = -1); // -1 - context item, else selected, -2 - cancel upload
 | ||||
| 	void deleteLayer(int selectedCount = 0); // 0 - context item
 | ||||
| 	void cancelUploadLayer(); | ||||
| 	void shareContactLayer(UserData *contact); | ||||
| 	void shareUrlLayer(const QString &url, const QString &text); | ||||
| 	void inlineSwitchLayer(const QString &botAndQuery); | ||||
|  |  | |||
|  | @ -204,11 +204,7 @@ void MainWindow::firstShow() { | |||
| 	psFirstShow(); | ||||
| 	updateTrayMenu(); | ||||
| 
 | ||||
| 	_mediaView = new MediaView(); | ||||
| } | ||||
| 
 | ||||
| QWidget *MainWindow::filedialogParent() { | ||||
| 	return (_mediaView && _mediaView->isVisible()) ? (QWidget*)_mediaView : (QWidget*)this; | ||||
| 	createMediaView(); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::clearWidgets() { | ||||
|  | @ -600,30 +596,6 @@ void MainWindow::layerHidden() { | |||
| 	checkHistoryActivation(); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::onReActivate() { | ||||
| 	if (auto w = App::wnd()) { | ||||
| 		if (auto f = QApplication::focusWidget()) { | ||||
| 			f->clearFocus(); | ||||
| 		} | ||||
| 		w->windowHandle()->requestActivate(); | ||||
| 		w->activate(); | ||||
| 		if (auto f = QApplication::focusWidget()) { | ||||
| 			f->clearFocus(); | ||||
| 		} | ||||
| 		w->setInnerFocus(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MainWindow::hideMediaview() { | ||||
|     if (_mediaView && !_mediaView->isHidden()) { | ||||
|         _mediaView->hide(); | ||||
| #if defined Q_OS_LINUX32 || defined Q_OS_LINUX64 | ||||
| 		onReActivate(); | ||||
| 		QTimer::singleShot(200, this, SLOT(onReActivate())); | ||||
| #endif | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool MainWindow::contentOverlapped(const QRect &globalRect) { | ||||
| 	if (_main && _main->contentOverlapped(globalRect)) return true; | ||||
| 	if (_layerBg && _layerBg->contentOverlapped(globalRect)) return true; | ||||
|  | @ -712,21 +684,6 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *e) { | |||
| 	return Platform::MainWindow::eventFilter(obj, e); | ||||
| } | ||||
| 
 | ||||
| bool MainWindow::minimizeToTray() { | ||||
|     if (App::quitting() || !psHasTrayIcon()) return false; | ||||
| 
 | ||||
| 	closeWithoutDestroy(); | ||||
|     if (cPlatform() == dbipWindows && trayIcon && !cSeenTrayTooltip()) { | ||||
| 		trayIcon->showMessage(str_const_toString(AppName), lang(lng_tray_icon_text), QSystemTrayIcon::Information, 10000); | ||||
| 		cSetSeenTrayTooltip(true); | ||||
| 		Local::writeSettings(); | ||||
| 	} | ||||
| 	updateIsActive(Global::OfflineBlurTimeout()); | ||||
| 	updateTrayMenu(); | ||||
| 	updateGlobalMenu(); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void MainWindow::updateTrayMenu(bool force) { | ||||
|     if (!trayIconMenu || (cPlatform() == dbipWindows && !force)) return; | ||||
| 
 | ||||
|  | @ -1450,7 +1407,6 @@ MainWindow::~MainWindow() { | |||
| 		_clearManager->stop(); | ||||
| 		_clearManager = nullptr; | ||||
| 	} | ||||
| 	delete _mediaView; | ||||
| 	delete trayIcon; | ||||
| 	delete trayIconMenu; | ||||
| } | ||||
|  |  | |||
|  | @ -80,8 +80,6 @@ public: | |||
| 
 | ||||
| 	void firstShow(); | ||||
| 
 | ||||
| 	QWidget *filedialogParent(); | ||||
| 
 | ||||
| 	void inactivePress(bool inactive); | ||||
| 	bool inactivePress() const; | ||||
| 
 | ||||
|  | @ -142,7 +140,6 @@ public: | |||
| 	void changingMsgId(HistoryItem *row, MsgId newId); | ||||
| 
 | ||||
| 	bool isActive(bool cached = true) const; | ||||
| 	void hideMediaview(); | ||||
| 
 | ||||
| 	QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) override; | ||||
| 
 | ||||
|  | @ -184,7 +181,6 @@ public slots: | |||
| 
 | ||||
| 	void quitFromTray(); | ||||
| 	void showFromTray(QSystemTrayIcon::ActivationReason reason = QSystemTrayIcon::Unknown); | ||||
| 	bool minimizeToTray(); | ||||
| 	void toggleTray(QSystemTrayIcon::ActivationReason reason = QSystemTrayIcon::Unknown); | ||||
| 	void toggleDisplayNotifyFromTray(); | ||||
| 
 | ||||
|  | @ -202,8 +198,6 @@ public slots: | |||
| 	void onLogout(); | ||||
| 	void updateGlobalMenu(); // for OS X top menu
 | ||||
| 
 | ||||
| 	void onReActivate(); | ||||
| 
 | ||||
| 	void app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button); | ||||
| 
 | ||||
| signals: | ||||
|  | @ -283,8 +277,6 @@ private: | |||
| 	using NotifyWhenAlerts = QMap<History*, NotifyWhenAlert>; | ||||
| 	NotifyWhenAlerts _notifyWhenAlerts; | ||||
| 
 | ||||
| 	MediaView *_mediaView = nullptr; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| class PreLaunchWindow : public TWidget { | ||||
|  |  | |||
|  | @ -200,7 +200,7 @@ mediaviewCaptionRadius: 2px; | |||
| 
 | ||||
| themePreviewSize: size(903px, 584px); | ||||
| themePreviewBg: windowBg; | ||||
| themePreviewOverlayOpacity: 0.7; | ||||
| themePreviewOverlayOpacity: 0.8; | ||||
| themePreviewMargin: margins(36px, 52px, 36px, 88px); | ||||
| themePreviewTitleTop: 14px; | ||||
| themePreviewTitleFg: windowBoldFg; | ||||
|  |  | |||
|  | @ -67,7 +67,7 @@ bool typeHasMediaOverview(MediaOverviewType type) { | |||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| MediaView::MediaView() : TWidget(App::wnd()) | ||||
| MediaView::MediaView(QWidget*) : TWidget(nullptr) | ||||
| , _animStarted(getms()) | ||||
| , _docDownload(this, lang(lng_media_download), st::mediaviewFileLink) | ||||
| , _docSaveAs(this, lang(lng_mediaview_save_as), st::mediaviewFileLink) | ||||
|  | @ -75,7 +75,8 @@ MediaView::MediaView() : TWidget(App::wnd()) | |||
| , _radial(animation(this, &MediaView::step_radial)) | ||||
| , _lastAction(-st::mediaviewDeltaFromLastAction, -st::mediaviewDeltaFromLastAction) | ||||
| , _a_state(animation(this, &MediaView::step_state)) | ||||
| , _dropdown(this, st::mediaviewDropdownMenu) { | ||||
| , _dropdown(this, st::mediaviewDropdownMenu) | ||||
| , _dropdownShowTimer(this) { | ||||
| 	TextCustomTagsMap custom; | ||||
| 	custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink())); | ||||
| 	_saveMsgText.setRichText(st::mediaviewSaveMsgStyle, lang(lng_mediaview_saved), _textDlgOptions, custom); | ||||
|  | @ -121,6 +122,8 @@ MediaView::MediaView() : TWidget(App::wnd()) | |||
| 	connect(_docCancel, SIGNAL(clicked()), this, SLOT(onSaveCancel())); | ||||
| 
 | ||||
| 	_dropdown->setHiddenCallback([this] { dropdownHidden(); }); | ||||
| 	_dropdownShowTimer->setSingleShot(true); | ||||
| 	connect(_dropdownShowTimer, SIGNAL(timeout()), this, SLOT(onDropdown())); | ||||
| } | ||||
| 
 | ||||
| void MediaView::moveToScreen() { | ||||
|  | @ -1333,8 +1336,9 @@ void MediaView::updateThemePreviewGeometry() { | |||
| 		auto previewRect = QRect((width() - st::themePreviewSize.width()) / 2, (height() - st::themePreviewSize.height()) / 2, st::themePreviewSize.width(), st::themePreviewSize.height()); | ||||
| 		_themePreviewRect = previewRect.marginsAdded(st::themePreviewMargin); | ||||
| 		if (_themeApply) { | ||||
| 			auto right = width() - _themePreviewRect.x() - _themePreviewRect.width() + st::themePreviewMargin.right(); | ||||
| 			_themeApply->moveToRight(right, _themePreviewRect.y() + _themePreviewRect.height() - st::themePreviewMargin.bottom() + (st::themePreviewMargin.bottom() - _themeApply->height()) / 2); | ||||
| 			auto right = qMax(width() - _themePreviewRect.x() - _themePreviewRect.width(), 0) + st::themePreviewMargin.right(); | ||||
| 			auto bottom = qMin(height(), _themePreviewRect.y() + _themePreviewRect.height()); | ||||
| 			_themeApply->moveToRight(right, bottom - st::themePreviewMargin.bottom() + (st::themePreviewMargin.bottom() - _themeApply->height()) / 2); | ||||
| 			right += _themeApply->width() + st::themePreviewButtonsSkip; | ||||
| 			_themeCancel->moveToRight(right, _themeApply->y()); | ||||
| 		} | ||||
|  | @ -2370,7 +2374,9 @@ bool MediaView::updateOverState(OverState newState) { | |||
| 	bool result = true; | ||||
| 	if (_over != newState) { | ||||
| 		if (newState == OverMore && !_ignoringDropdown) { | ||||
| 			QTimer::singleShot(0, this, SLOT(onDropdown())); | ||||
| 			_dropdownShowTimer->start(0); | ||||
| 		} else { | ||||
| 			_dropdownShowTimer->stop(); | ||||
| 		} | ||||
| 		updateOverRect(_over); | ||||
| 		updateOverRect(newState); | ||||
|  | @ -2393,7 +2399,7 @@ bool MediaView::updateOverState(OverState newState) { | |||
| 			if (i != _animOpacities.end()) { | ||||
| 				i->start(1); | ||||
| 			} else { | ||||
| 				_animOpacities.insert(_over, anim::value()); | ||||
| 				_animOpacities.insert(_over, anim::value(0, 1)); | ||||
| 			} | ||||
| 			if (!_a_state.animating()) _a_state.start(); | ||||
| 		} | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ class MediaView : public TWidget, private base::Subscriber, public RPCSender, pu | |||
| 	Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
| 	MediaView(); | ||||
| 	MediaView(QWidget*); | ||||
| 
 | ||||
| 	void setVisible(bool visible) override; | ||||
| 
 | ||||
|  | @ -330,6 +330,7 @@ private: | |||
| 
 | ||||
| 	Ui::PopupMenu *_menu = nullptr; | ||||
| 	object_ptr<Ui::DropdownMenu> _dropdown; | ||||
| 	object_ptr<QTimer> _dropdownShowTimer; | ||||
| 
 | ||||
| 	struct ActionData { | ||||
| 		QString text; | ||||
|  |  | |||
|  | @ -2276,16 +2276,21 @@ void OverviewWidget::confirmDeleteContextItem() { | |||
| 	auto item = App::contextItem(); | ||||
| 	if (!item || item->type() != HistoryItemMsg) return; | ||||
| 
 | ||||
| 	auto message = item->toHistoryMessage(); | ||||
| 	App::main()->deleteLayer((message && message->uploading()) ? -2 : -1); | ||||
| 	if (auto message = item->toHistoryMessage()) { | ||||
| 		if (message->uploading()) { | ||||
| 			App::main()->cancelUploadLayer(); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 	App::main()->deleteLayer(); | ||||
| } | ||||
| 
 | ||||
| void OverviewWidget::confirmDeleteSelectedItems() { | ||||
| 	SelectedItemSet sel; | ||||
| 	_inner->fillSelectedItems(sel); | ||||
| 	if (sel.isEmpty()) return; | ||||
| 	SelectedItemSet selected; | ||||
| 	_inner->fillSelectedItems(selected); | ||||
| 	if (selected.isEmpty()) return; | ||||
| 
 | ||||
| 	App::main()->deleteLayer(sel.size()); | ||||
| 	App::main()->deleteLayer(selected.size()); | ||||
| } | ||||
| 
 | ||||
| void OverviewWidget::deleteContextItem(bool forEveryone) { | ||||
|  |  | |||
|  | @ -51,8 +51,6 @@ public: | |||
| 
 | ||||
| 	virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0; | ||||
| 
 | ||||
| 	void closeWithoutDestroy() override; | ||||
| 
 | ||||
| 	int getCustomTitleHeight() const { | ||||
| 		return _customTitleHeight; | ||||
| 	} | ||||
|  | @ -103,6 +101,8 @@ protected: | |||
| 
 | ||||
| 	QTimer psUpdatedPositionTimer; | ||||
| 
 | ||||
| 	void closeWithoutDestroy() override; | ||||
| 
 | ||||
| private: | ||||
| 	void createGlobalMenu(); | ||||
| 	void updateTitleCounter(); | ||||
|  |  | |||
|  | @ -927,7 +927,7 @@ void PhotoCancelClickHandler::onClickImpl() const { | |||
| 			if (auto media = item->getMedia()) { | ||||
| 				if (media->type() == MediaTypePhoto && static_cast<HistoryPhoto*>(media)->photo() == data) { | ||||
| 					App::contextItem(item); | ||||
| 					App::main()->deleteLayer(-2); | ||||
| 					App::main()->cancelUploadLayer(); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | @ -1240,7 +1240,7 @@ void DocumentCancelClickHandler::onClickImpl() const { | |||
| 			if (auto media = item->getMedia()) { | ||||
| 				if (media->getDocument() == data) { | ||||
| 					App::contextItem(item); | ||||
| 					App::main()->deleteLayer(-2); | ||||
| 					App::main()->cancelUploadLayer(); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  |  | |||
|  | @ -79,6 +79,13 @@ public: | |||
| 
 | ||||
| Radiobuttons radiobuttons; | ||||
| 
 | ||||
| TextParseOptions _checkboxOptions = { | ||||
| 	TextParseMultiline, // flags
 | ||||
| 	0, // maxw
 | ||||
| 	0, // maxh
 | ||||
| 	Qt::LayoutDirectionAuto, // dir
 | ||||
| }; | ||||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| void RadiobuttonGroup::remove(Radiobutton * const &radio) { | ||||
|  | @ -90,17 +97,11 @@ void RadiobuttonGroup::remove(Radiobutton * const &radio) { | |||
| 
 | ||||
| Checkbox::Checkbox(QWidget *parent, const QString &text, bool checked, const style::Checkbox &st) : RippleButton(parent, st.ripple) | ||||
| , _st(st) | ||||
| , _text(text) | ||||
| , _fullText(text) | ||||
| , _textWidth(st.font->width(text)) | ||||
| , _text(_st.style, text, _checkboxOptions) | ||||
| , _checked(checked) { | ||||
| 	if (_st.width <= 0) { | ||||
| 		resizeToWidth(_textWidth - _st.width); | ||||
| 		resizeToWidth(_text.maxWidth() - _st.width); | ||||
| 	} else { | ||||
| 		if (_st.width < _st.textPosition.x() + _textWidth + (_st.textPosition.x() - _st.diameter)) { | ||||
| 			_text = _st.font->elided(_fullText, qMax(_st.width - (_st.textPosition.x() + (_st.textPosition.x() - _st.diameter)), 1)); | ||||
| 			_textWidth = _st.font->width(_text); | ||||
| 		} | ||||
| 		resizeToWidth(_st.width); | ||||
| 	} | ||||
| 	_checkRect = myrtlrect(_st.margin.left(), _st.margin.top(), _st.diameter, _st.diameter); | ||||
|  | @ -129,7 +130,7 @@ void Checkbox::finishAnimations() { | |||
| } | ||||
| 
 | ||||
| int Checkbox::naturalWidth() const { | ||||
| 	return _st.textPosition.x() + _st.font->width(_fullText); | ||||
| 	return _st.textPosition.x() + _text.maxWidth(); | ||||
| } | ||||
| 
 | ||||
| void Checkbox::paintEvent(QPaintEvent *e) { | ||||
|  | @ -157,9 +158,10 @@ void Checkbox::paintEvent(QPaintEvent *e) { | |||
| 	} | ||||
| 	if (_checkRect.contains(e->rect())) return; | ||||
| 
 | ||||
| 	auto textWidth = qMax(width() - (_st.textPosition.x() + (_st.textPosition.x() - _st.diameter)), 1); | ||||
| 
 | ||||
| 	p.setPen(_st.textFg); | ||||
| 	p.setFont(_st.font); | ||||
| 	p.drawTextLeft(_st.margin.left() + _st.textPosition.x(), _st.margin.top() + _st.textPosition.y(), width(), _text, _textWidth); | ||||
| 	_text.drawLeftElided(p, _st.margin.left() + _st.textPosition.x(), _st.margin.top() + _st.textPosition.y(), textWidth, width()); | ||||
| } | ||||
| 
 | ||||
| void Checkbox::onClicked() { | ||||
|  | @ -195,19 +197,13 @@ QPoint Checkbox::prepareRippleStartPosition() const { | |||
| 
 | ||||
| Radiobutton::Radiobutton(QWidget *parent, const QString &group, int32 value, const QString &text, bool checked, const style::Checkbox &st) : RippleButton(parent, st.ripple) | ||||
| , _st(st) | ||||
| , _text(text) | ||||
| , _fullText(text) | ||||
| , _textWidth(st.font->width(text)) | ||||
| , _text(_st.style, text, _checkboxOptions) | ||||
| , _checked(checked) | ||||
| , _group(radiobuttons.reg(group)) | ||||
| , _value(value) { | ||||
| 	if (_st.width <= 0) { | ||||
| 		resizeToWidth(_textWidth - _st.width); | ||||
| 		resizeToWidth(_text.maxWidth() - _st.width); | ||||
| 	} else { | ||||
| 		if (_st.width < _st.textPosition.x() + _textWidth + (_st.textPosition.x() - _st.diameter)) { | ||||
| 			_text = _st.font->elided(_fullText, qMax(_st.width - (_st.textPosition.x() + (_st.textPosition.x() - _st.diameter)), 1)); | ||||
| 			_textWidth = _st.font->width(_text); | ||||
| 		} | ||||
| 		resizeToWidth(_st.width); | ||||
| 	} | ||||
| 	_checkRect = myrtlrect(_st.margin.left(), _st.margin.top(), _st.diameter, _st.diameter); | ||||
|  | @ -235,7 +231,7 @@ void Radiobutton::setChecked(bool checked) { | |||
| } | ||||
| 
 | ||||
| int Radiobutton::naturalWidth() const { | ||||
| 	return _st.textPosition.x() + _st.font->width(_fullText); | ||||
| 	return _st.textPosition.x() + _text.maxWidth(); | ||||
| } | ||||
| 
 | ||||
| void Radiobutton::paintEvent(QPaintEvent *e) { | ||||
|  | @ -278,9 +274,10 @@ void Radiobutton::paintEvent(QPaintEvent *e) { | |||
| 	} | ||||
| 	if (_checkRect.contains(e->rect())) return; | ||||
| 
 | ||||
| 	auto textWidth = qMax(width() - (_st.textPosition.x() + (_st.textPosition.x() - _st.diameter)), 1); | ||||
| 
 | ||||
| 	p.setPen(_st.textFg); | ||||
| 	p.setFont(_st.font); | ||||
| 	p.drawTextLeft(_st.margin.left() + _st.textPosition.x(), _st.margin.top() + _st.textPosition.y(), width(), _text, _textWidth); | ||||
| 	_text.drawLeftElided(p, _st.margin.left() + _st.textPosition.x(), _st.margin.top() + _st.textPosition.y(), textWidth, width()); | ||||
| } | ||||
| 
 | ||||
| void Radiobutton::onClicked() { | ||||
|  |  | |||
|  | @ -63,8 +63,7 @@ signals: | |||
| private: | ||||
| 	const style::Checkbox &_st; | ||||
| 
 | ||||
| 	QString _text, _fullText; | ||||
| 	int32 _textWidth; | ||||
| 	Text _text; | ||||
| 	QRect _checkRect; | ||||
| 
 | ||||
| 	bool _checked; | ||||
|  | @ -76,12 +75,12 @@ class Radiobutton : public RippleButton { | |||
| 	Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
| 	Radiobutton(QWidget *parent, const QString &group, int32 value, const QString &text, bool checked = false, const style::Checkbox &st = st::defaultCheckbox); | ||||
| 	Radiobutton(QWidget *parent, const QString &group, int value, const QString &text, bool checked = false, const style::Checkbox &st = st::defaultCheckbox); | ||||
| 
 | ||||
| 	bool checked() const; | ||||
| 	void setChecked(bool checked); | ||||
| 
 | ||||
| 	int32 val() const { | ||||
| 	int val() const { | ||||
| 		return _value; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -112,15 +111,14 @@ private: | |||
| 
 | ||||
| 	const style::Checkbox &_st; | ||||
| 
 | ||||
| 	QString _text, _fullText; | ||||
| 	int32 _textWidth; | ||||
| 	Text _text; | ||||
| 	QRect _checkRect; | ||||
| 
 | ||||
| 	bool _checked; | ||||
| 	Animation _a_checked; | ||||
| 
 | ||||
| 	void *_group; | ||||
| 	int32 _value; | ||||
| 	int _value; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -311,7 +311,8 @@ bool InnerDropdown::eventFilter(QObject *obj, QEvent *e) { | |||
| int InnerDropdown::resizeGetHeight(int newWidth) { | ||||
| 	auto newHeight = _st.padding.top() + _st.scrollMargin.top() + _st.scrollMargin.bottom() + _st.padding.bottom(); | ||||
| 	if (auto widget = static_cast<TWidget*>(_scroll->widget())) { | ||||
| 		widget->resizeToWidth(newWidth - _st.padding.left() - _st.padding.right() - _st.scrollMargin.left() - _st.scrollMargin.right()); | ||||
| 		auto containerWidth = newWidth - _st.padding.left() - _st.padding.right() - _st.scrollMargin.left() - _st.scrollMargin.right(); | ||||
| 		widget->resizeToWidth(containerWidth); | ||||
| 		newHeight += widget->height(); | ||||
| 	} | ||||
| 	if (_maxHeight > 0) { | ||||
|  | @ -332,7 +333,7 @@ void InnerDropdown::Container::setVisibleTopBottom(int visibleTop, int visibleBo | |||
| } | ||||
| 
 | ||||
| void InnerDropdown::Container::resizeToContent() { | ||||
| 	auto newWidth = _st.scrollPadding.top() + _st.scrollPadding.bottom(); | ||||
| 	auto newWidth = _st.scrollPadding.left() + _st.scrollPadding.right(); | ||||
| 	auto newHeight = _st.scrollPadding.top() + _st.scrollPadding.bottom(); | ||||
| 	if (auto child = static_cast<TWidget*>(children().front())) { | ||||
| 		newWidth += child->width(); | ||||
|  | @ -344,8 +345,8 @@ void InnerDropdown::Container::resizeToContent() { | |||
| } | ||||
| 
 | ||||
| int InnerDropdown::Container::resizeGetHeight(int newWidth) { | ||||
| 	int innerWidth = newWidth - _st.scrollPadding.left() - _st.scrollPadding.right(); | ||||
| 	int result = _st.scrollPadding.top() + _st.scrollPadding.bottom(); | ||||
| 	auto innerWidth = newWidth - _st.scrollPadding.left() - _st.scrollPadding.right(); | ||||
| 	auto result = _st.scrollPadding.top() + _st.scrollPadding.bottom(); | ||||
| 	if (auto child = static_cast<TWidget*>(children().front())) { | ||||
| 		child->resizeToWidth(innerWidth); | ||||
| 		child->moveToLeft(_st.scrollPadding.left(), _st.scrollPadding.top()); | ||||
|  |  | |||
|  | @ -34,6 +34,7 @@ TextParseOptions _labelOptions = { | |||
| 	0, // maxh
 | ||||
| 	Qt::LayoutDirectionAuto, // dir
 | ||||
| }; | ||||
| 
 | ||||
| TextParseOptions _labelMarkedOptions = { | ||||
| 	TextParseMultiline | TextParseRichText | TextParseLinks | TextParseHashtags | TextParseMentions | TextParseBotCommands | TextParseMono, // flags
 | ||||
| 	0, // maxw
 | ||||
|  |  | |||
|  | @ -109,7 +109,7 @@ Checkbox { | |||
| 	radioSkip: pixels; | ||||
| 	checkIcon: icon; | ||||
| 
 | ||||
| 	font: font; | ||||
| 	style: TextStyle; | ||||
| 	duration: int; | ||||
| 
 | ||||
| 	rippleAreaPosition: point; | ||||
|  | @ -641,7 +641,7 @@ defaultCheckbox: Checkbox { | |||
| 	checkIcon: defaultCheckboxIcon; | ||||
| 	radioSkip: 65px; // * 0.1 | ||||
| 
 | ||||
| 	font: normalFont; | ||||
| 	style: defaultTextStyle; | ||||
| 	duration: 120; | ||||
| 
 | ||||
| 	rippleAreaSize: 38px; | ||||
|  |  | |||
|  | @ -25,6 +25,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org | |||
| #include "styles/style_window.h" | ||||
| #include "platform/platform_window_title.h" | ||||
| #include "window/window_theme.h" | ||||
| #include "mediaview.h" | ||||
| #include "mainwindow.h" | ||||
| 
 | ||||
| namespace Window { | ||||
| 
 | ||||
|  | @ -43,6 +45,57 @@ MainWindow::MainWindow() : QWidget() | |||
| 	subscribe(Global::RefUnreadCounterUpdate(), [this] { updateUnreadCounter(); }); | ||||
| } | ||||
| 
 | ||||
| bool MainWindow::hideNoQuit() { | ||||
| 	if (_mediaView && !_mediaView->isHidden()) { | ||||
| 		_mediaView->hide(); | ||||
| 		return true; | ||||
| 	} | ||||
| 	if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { | ||||
| 		if (minimizeToTray()) { | ||||
| 			Ui::showChatsList(); | ||||
| 			return true; | ||||
| 		} | ||||
| 	} else if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { | ||||
| 		closeWithoutDestroy(); | ||||
| 		updateIsActive(Global::OfflineBlurTimeout()); | ||||
| 		updateGlobalMenu(); | ||||
| 		Ui::showChatsList(); | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void MainWindow::hideMediaview() { | ||||
| 	if (_mediaView && !_mediaView->isHidden()) { | ||||
| 		_mediaView->hide(); | ||||
| #if defined Q_OS_LINUX32 || defined Q_OS_LINUX64 | ||||
| 		onReActivate(); | ||||
| 		QTimer::singleShot(200, this, SLOT(onReActivate())); | ||||
| #endif | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void MainWindow::onReActivate() { | ||||
| 	if (auto w = App::wnd()) { | ||||
| 		if (auto f = QApplication::focusWidget()) { | ||||
| 			f->clearFocus(); | ||||
| 		} | ||||
| 		w->windowHandle()->requestActivate(); | ||||
| 		w->activate(); | ||||
| 		if (auto f = QApplication::focusWidget()) { | ||||
| 			f->clearFocus(); | ||||
| 		} | ||||
| 		w->setInnerFocus(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| QWidget *MainWindow::filedialogParent() { | ||||
| 	return (_mediaView && _mediaView->isVisible()) ? (QWidget*)_mediaView : (QWidget*)this; | ||||
| } | ||||
| 
 | ||||
| void MainWindow::createMediaView() { | ||||
| 	_mediaView.create(nullptr); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::init() { | ||||
| 	initHook(); | ||||
| 
 | ||||
|  | @ -197,11 +250,25 @@ void MainWindow::savePosition(Qt::WindowState state) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| MainWindow::~MainWindow() { | ||||
| bool MainWindow::minimizeToTray() { | ||||
| 	if (App::quitting() || !psHasTrayIcon()) return false; | ||||
| 
 | ||||
| 	closeWithoutDestroy(); | ||||
| 	if (cPlatform() == dbipWindows && trayIcon && !cSeenTrayTooltip()) { | ||||
| 		trayIcon->showMessage(str_const_toString(AppName), lang(lng_tray_icon_text), QSystemTrayIcon::Information, 10000); | ||||
| 		cSetSeenTrayTooltip(true); | ||||
| 		Local::writeSettings(); | ||||
| 	} | ||||
| 	updateIsActive(Global::OfflineBlurTimeout()); | ||||
| 	updateTrayMenu(); | ||||
| 	updateGlobalMenu(); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void MainWindow::closeWithoutDestroy() { | ||||
| 	hide(); | ||||
| } | ||||
| 
 | ||||
| MainWindow::~MainWindow() = default; | ||||
| 
 | ||||
| } // namespace Window
 | ||||
|  |  | |||
|  | @ -22,6 +22,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org | |||
| 
 | ||||
| #include "window/window_title.h" | ||||
| 
 | ||||
| class MediaView; | ||||
| 
 | ||||
| namespace Window { | ||||
| 
 | ||||
| class TitleWidget; | ||||
|  | @ -32,6 +34,9 @@ class MainWindow : public QWidget, protected base::Subscriber { | |||
| public: | ||||
| 	MainWindow(); | ||||
| 
 | ||||
| 	bool hideNoQuit(); | ||||
| 	void hideMediaview(); | ||||
| 
 | ||||
| 	void init(); | ||||
| 	HitTestResult hitTest(const QPoint &p) const; | ||||
| 
 | ||||
|  | @ -46,7 +51,7 @@ public: | |||
| 		return _titleText; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void closeWithoutDestroy(); | ||||
| 	QWidget *filedialogParent(); | ||||
| 
 | ||||
| 	virtual ~MainWindow(); | ||||
| 
 | ||||
|  | @ -54,6 +59,9 @@ public: | |||
| 		return _body.data(); | ||||
| 	} | ||||
| 
 | ||||
| public slots: | ||||
| 	bool minimizeToTray(); | ||||
| 
 | ||||
| protected: | ||||
| 	void resizeEvent(QResizeEvent *e) override; | ||||
| 
 | ||||
|  | @ -71,15 +79,22 @@ protected: | |||
| 	virtual void unreadCounterChangedHook() { | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void closeWithoutDestroy() { | ||||
| 		hide(); | ||||
| 	} | ||||
| 
 | ||||
| 	// This one is overriden in Windows for historical reasons.
 | ||||
| 	virtual int32 screenNameChecksum(const QString &name) const; | ||||
| 
 | ||||
| 	void setPositionInited(); | ||||
| 
 | ||||
| 	void createMediaView(); | ||||
| 
 | ||||
| private slots: | ||||
| 	void savePositionByTimer() { | ||||
| 		savePosition(); | ||||
| 	} | ||||
| 	void onReActivate(); | ||||
| 
 | ||||
| private: | ||||
| 	void updatePalette(); | ||||
|  | @ -95,6 +110,8 @@ private: | |||
| 
 | ||||
| 	QString _titleText; | ||||
| 
 | ||||
| 	object_ptr<MediaView> _mediaView = { nullptr }; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| } // namespace Window
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue