Ask export path with other export options.
This commit is contained in:
		
							parent
							
								
									10a0c6a086
								
							
						
					
					
						commit
						ae18ece549
					
				
					 12 changed files with 310 additions and 184 deletions
				
			
		|  | @ -1676,7 +1676,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| "lng_export_option_gifs" = "Animated GIFs"; | "lng_export_option_gifs" = "Animated GIFs"; | ||||||
| "lng_export_option_files" = "Files"; | "lng_export_option_files" = "Files"; | ||||||
| "lng_export_option_size_limit" = "Size limit: {size}"; | "lng_export_option_size_limit" = "Size limit: {size}"; | ||||||
| "lng_export_header_format" = "Format"; | "lng_export_header_format" = "Location and format"; | ||||||
|  | "lng_export_option_location" = "Download path: {path}"; | ||||||
| "lng_export_option_text" = "Human-readable text"; | "lng_export_option_text" = "Human-readable text"; | ||||||
| "lng_export_option_json" = "Machine-readable JSON"; | "lng_export_option_json" = "Machine-readable JSON"; | ||||||
| "lng_export_start" = "Export"; | "lng_export_start" = "Export"; | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ void AboutBox::prepare() { | ||||||
| 
 | 
 | ||||||
| 	addButton(langFactory(lng_close), [this] { closeBox(); }); | 	addButton(langFactory(lng_close), [this] { closeBox(); }); | ||||||
| 
 | 
 | ||||||
| 	const auto linkHook = [](const ClickHandlerPtr &link, auto button) { | 	const auto linkFilter = [](const ClickHandlerPtr &link, auto button) { | ||||||
| 		if (const auto url = dynamic_cast<UrlClickHandler*>(link.get())) { | 		if (const auto url = dynamic_cast<UrlClickHandler*>(link.get())) { | ||||||
| 			url->UrlClickHandler::onClick(button); | 			url->UrlClickHandler::onClick(button); | ||||||
| 			return false; | 			return false; | ||||||
|  | @ -40,9 +40,9 @@ void AboutBox::prepare() { | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	_text3->setRichText(lng_about_text_3(lt_faq_open, qsl("[a href=\"%1\"]").arg(telegramFaqLink()), lt_faq_close, qsl("[/a]"))); | 	_text3->setRichText(lng_about_text_3(lt_faq_open, qsl("[a href=\"%1\"]").arg(telegramFaqLink()), lt_faq_close, qsl("[/a]"))); | ||||||
| 	_text1->setClickHandlerHook(linkHook); | 	_text1->setClickHandlerFilter(linkFilter); | ||||||
| 	_text2->setClickHandlerHook(linkHook); | 	_text2->setClickHandlerFilter(linkFilter); | ||||||
| 	_text3->setClickHandlerHook(linkHook); | 	_text3->setClickHandlerFilter(linkFilter); | ||||||
| 
 | 
 | ||||||
| 	_version->setClickedCallback([this] { showVersionHistory(); }); | 	_version->setClickedCallback([this] { showVersionHistory(); }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -710,7 +710,7 @@ object_ptr<Ui::RpWidget> Controller::createInviteLinkEdit() { | ||||||
| 	_controls.inviteLink->setSelectable(true); | 	_controls.inviteLink->setSelectable(true); | ||||||
| 	_controls.inviteLink->setContextCopyText(QString()); | 	_controls.inviteLink->setContextCopyText(QString()); | ||||||
| 	_controls.inviteLink->setBreakEverywhere(true); | 	_controls.inviteLink->setBreakEverywhere(true); | ||||||
| 	_controls.inviteLink->setClickHandlerHook([this](auto&&...) { | 	_controls.inviteLink->setClickHandlerFilter([=](auto&&...) { | ||||||
| 		Application::clipboard()->setText(inviteLinkText()); | 		Application::clipboard()->setText(inviteLinkText()); | ||||||
| 		Ui::Toast::Show(lang(lng_group_invite_copied)); | 		Ui::Toast::Show(lang(lng_group_invite_copied)); | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
|  | @ -37,6 +37,12 @@ exportFileSizeLabel: LabelSimple(defaultLabelSimple) { | ||||||
| } | } | ||||||
| exportFileSizePadding: margins(22px, 8px, 22px, 8px); | exportFileSizePadding: margins(22px, 8px, 22px, 8px); | ||||||
| exportFileSizeLabelBottom: 18px; | exportFileSizeLabelBottom: 18px; | ||||||
|  | 
 | ||||||
|  | exportLocationLabel: FlatLabel(boxLabel) { | ||||||
|  | 	maxHeight: 21px; | ||||||
|  | } | ||||||
|  | exportLocationPadding: margins(22px, 8px, 22px, 8px); | ||||||
|  | 
 | ||||||
| exportErrorLabel: FlatLabel(boxLabel) { | exportErrorLabel: FlatLabel(boxLabel) { | ||||||
| 	minWidth: 175px; | 	minWidth: 175px; | ||||||
| 	align: align(top); | 	align: align(top); | ||||||
|  |  | ||||||
|  | @ -59,21 +59,13 @@ int SizeLimitByIndex(int index) { | ||||||
| 
 | 
 | ||||||
| SettingsWidget::SettingsWidget(QWidget *parent) | SettingsWidget::SettingsWidget(QWidget *parent) | ||||||
| : RpWidget(parent) { | : RpWidget(parent) { | ||||||
| 	if (Global::DownloadPath().isEmpty()) { | 	_data.path = psDownloadPath(); | ||||||
| 		_data.path = psDownloadPath(); |  | ||||||
| 	} else if (Global::DownloadPath() == qsl("tmp")) { |  | ||||||
| 		_data.path = cTempDir(); |  | ||||||
| 	} else { |  | ||||||
| 		_data.path = Global::DownloadPath(); |  | ||||||
| 	} |  | ||||||
| 	_data.internalLinksDomain = Global::InternalLinksDomain(); | 	_data.internalLinksDomain = Global::InternalLinksDomain(); | ||||||
| 
 | 
 | ||||||
| 	setupContent(); | 	setupContent(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SettingsWidget::setupContent() { | void SettingsWidget::setupContent() { | ||||||
| 	using namespace rpl::mappers; |  | ||||||
| 
 |  | ||||||
| 	const auto scroll = Ui::CreateChild<Ui::ScrollArea>( | 	const auto scroll = Ui::CreateChild<Ui::ScrollArea>( | ||||||
| 		this, | 		this, | ||||||
| 		st::boxLayerScroll); | 		st::boxLayerScroll); | ||||||
|  | @ -82,6 +74,148 @@ void SettingsWidget::setupContent() { | ||||||
| 		object_ptr<Ui::VerticalLayout>(scroll))); | 		object_ptr<Ui::VerticalLayout>(scroll))); | ||||||
| 	const auto content = static_cast<Ui::VerticalLayout*>(wrap->entity()); | 	const auto content = static_cast<Ui::VerticalLayout*>(wrap->entity()); | ||||||
| 
 | 
 | ||||||
|  | 	const auto buttons = setupButtons(scroll, wrap); | ||||||
|  | 	setupOptions(content); | ||||||
|  | 	setupPathAndFormat(content); | ||||||
|  | 
 | ||||||
|  | 	_refreshButtons.fire({}); | ||||||
|  | 
 | ||||||
|  | 	sizeValue( | ||||||
|  | 	) | rpl::start_with_next([=](QSize size) { | ||||||
|  | 		scroll->resize(size.width(), size.height() - buttons->height()); | ||||||
|  | 		wrap->resizeToWidth(size.width()); | ||||||
|  | 		content->resizeToWidth(size.width()); | ||||||
|  | 	}, lifetime()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SettingsWidget::setupOptions(not_null<Ui::VerticalLayout*> container) { | ||||||
|  | 	addOption( | ||||||
|  | 		container, | ||||||
|  | 		lng_export_option_info, | ||||||
|  | 		Type::PersonalInfo | Type::Userpics); | ||||||
|  | 	addOption(container, lng_export_option_contacts, Type::Contacts); | ||||||
|  | 	addOption(container, lng_export_option_sessions, Type::Sessions); | ||||||
|  | 	addHeader(container, lng_export_header_chats); | ||||||
|  | 	addOption( | ||||||
|  | 		container, | ||||||
|  | 		lng_export_option_personal_chats, | ||||||
|  | 		Type::PersonalChats); | ||||||
|  | 	addOption(container, lng_export_option_bot_chats, Type::BotChats); | ||||||
|  | 	addChatOption( | ||||||
|  | 		container, | ||||||
|  | 		lng_export_option_private_groups, | ||||||
|  | 		Type::PrivateGroups); | ||||||
|  | 	addChatOption( | ||||||
|  | 		container, | ||||||
|  | 		lng_export_option_private_channels, | ||||||
|  | 		Type::PrivateChannels); | ||||||
|  | 	addChatOption( | ||||||
|  | 		container, | ||||||
|  | 		lng_export_option_public_groups, | ||||||
|  | 		Type::PublicGroups); | ||||||
|  | 	addChatOption( | ||||||
|  | 		container, | ||||||
|  | 		lng_export_option_public_channels, | ||||||
|  | 		Type::PublicChannels); | ||||||
|  | 
 | ||||||
|  | 	setupMediaOptions(container); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SettingsWidget::setupMediaOptions( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container) { | ||||||
|  | 	const auto mediaWrap = container->add( | ||||||
|  | 		object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>( | ||||||
|  | 			container, | ||||||
|  | 			object_ptr<Ui::VerticalLayout>(container))); | ||||||
|  | 	const auto media = mediaWrap->entity(); | ||||||
|  | 	addHeader(media, lng_export_header_media); | ||||||
|  | 	addMediaOption(media, lng_export_option_photos, MediaType::Photo); | ||||||
|  | 	addMediaOption(media, lng_export_option_video_files, MediaType::Video); | ||||||
|  | 	addMediaOption(media, lng_export_option_voice_messages, MediaType::VoiceMessage); | ||||||
|  | 	addMediaOption(media, lng_export_option_video_messages, MediaType::VideoMessage); | ||||||
|  | 	addMediaOption(media, lng_export_option_stickers, MediaType::Sticker); | ||||||
|  | 	addMediaOption(media, lng_export_option_gifs, MediaType::GIF); | ||||||
|  | 	addMediaOption(media, lng_export_option_files, MediaType::File); | ||||||
|  | 	addSizeSlider(media); | ||||||
|  | 
 | ||||||
|  | 	_dataTypesChanges.events_starting_with_copy( | ||||||
|  | 		_data.types | ||||||
|  | 	) | rpl::start_with_next([=](Settings::Types types) { | ||||||
|  | 		mediaWrap->toggle((types & (Type::PersonalChats | ||||||
|  | 			| Type::BotChats | ||||||
|  | 			| Type::PrivateGroups | ||||||
|  | 			| Type::PrivateChannels | ||||||
|  | 			| Type::PublicGroups | ||||||
|  | 			| Type::PublicChannels)) != 0, anim::type::normal); | ||||||
|  | 	}, mediaWrap->lifetime()); | ||||||
|  | 
 | ||||||
|  | 	widthValue( | ||||||
|  | 	) | rpl::start_with_next([=](int width) { | ||||||
|  | 		mediaWrap->resizeToWidth(width); | ||||||
|  | 	}, mediaWrap->lifetime()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SettingsWidget::setupPathAndFormat( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container) { | ||||||
|  | 	const auto formatGroup = std::make_shared<Ui::RadioenumGroup<Format>>( | ||||||
|  | 		_data.format); | ||||||
|  | 	formatGroup->setChangedCallback([=](Format format) { | ||||||
|  | 		_data.format = format; | ||||||
|  | 	}); | ||||||
|  | 	const auto addFormatOption = [&](LangKey key, Format format) { | ||||||
|  | 		const auto radio = container->add( | ||||||
|  | 			object_ptr<Ui::Radioenum<Format>>( | ||||||
|  | 				container, | ||||||
|  | 				formatGroup, | ||||||
|  | 				format, | ||||||
|  | 				lang(key), | ||||||
|  | 				st::defaultBoxCheckbox), | ||||||
|  | 			st::exportSettingPadding); | ||||||
|  | 	}; | ||||||
|  | 	addHeader(container, lng_export_header_format); | ||||||
|  | 	addLocationLabel(container); | ||||||
|  | 	addFormatOption(lng_export_option_text, Format::Text); | ||||||
|  | 	addFormatOption(lng_export_option_json, Format::Json); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SettingsWidget::addLocationLabel( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container) { | ||||||
|  | 	auto pathLabel = _locationChanges.events_starting_with_copy( | ||||||
|  | 		_data.path | ||||||
|  | 	) | rpl::map([](const QString &path) { | ||||||
|  | 		const auto text = (path == psDownloadPath()) | ||||||
|  | 			? QString("Downloads/Telegram Desktop") | ||||||
|  | 			: path; | ||||||
|  | 		auto pathLink = TextWithEntities{ | ||||||
|  | 			QDir::toNativeSeparators(text), | ||||||
|  | 			EntitiesInText() | ||||||
|  | 		}; | ||||||
|  | 		pathLink.entities.push_back(EntityInText( | ||||||
|  | 			EntityInTextCustomUrl, | ||||||
|  | 			0, | ||||||
|  | 			text.size(), | ||||||
|  | 			"internal:edit_export_path")); | ||||||
|  | 		return lng_export_option_location__generic<TextWithEntities>( | ||||||
|  | 			lt_path, | ||||||
|  | 			pathLink); | ||||||
|  | 	}); | ||||||
|  | 	const auto label = container->add( | ||||||
|  | 		object_ptr<Ui::FlatLabel>( | ||||||
|  | 			container, | ||||||
|  | 			std::move(pathLabel), | ||||||
|  | 			st::exportLocationLabel), | ||||||
|  | 		st::exportLocationPadding); | ||||||
|  | 	label->setClickHandlerFilter([=](auto&&...) { | ||||||
|  | 		chooseFolder(); | ||||||
|  | 		return false; | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | not_null<Ui::RpWidget*> SettingsWidget::setupButtons( | ||||||
|  | 		not_null<Ui::ScrollArea*> scroll, | ||||||
|  | 		not_null<Ui::RpWidget*> wrap) { | ||||||
|  | 	using namespace rpl::mappers; | ||||||
|  | 
 | ||||||
| 	const auto buttonsPadding = st::boxButtonPadding; | 	const auto buttonsPadding = st::boxButtonPadding; | ||||||
| 	const auto buttonsHeight = buttonsPadding.top() | 	const auto buttonsHeight = buttonsPadding.top() | ||||||
| 		+ st::defaultBoxButton.height | 		+ st::defaultBoxButton.height | ||||||
|  | @ -101,170 +235,125 @@ void SettingsWidget::setupContent() { | ||||||
| 	) | rpl::map([=](int top) { | 	) | rpl::map([=](int top) { | ||||||
| 		return top < scroll->scrollTopMax(); | 		return top < scroll->scrollTopMax(); | ||||||
| 	})); | 	})); | ||||||
| 	const auto refreshButtonsCallback = [=] { | 
 | ||||||
|  | 	_refreshButtons.events( | ||||||
|  | 	) | rpl::start_with_next([=] { | ||||||
| 		refreshButtons(buttons); | 		refreshButtons(buttons); | ||||||
| 	}; | 		topShadow->raise(); | ||||||
| 	const auto addHeader = [&]( | 		bottomShadow->raise(); | ||||||
| 			not_null<Ui::VerticalLayout*> container, | 	}, buttons->lifetime()); | ||||||
| 			LangKey key) { |  | ||||||
| 		container->add( |  | ||||||
| 			object_ptr<Ui::FlatLabel>( |  | ||||||
| 				container, |  | ||||||
| 				lang(key), |  | ||||||
| 				Ui::FlatLabel::InitType::Simple, |  | ||||||
| 				st::exportHeaderLabel), |  | ||||||
| 			st::exportHeaderPadding); |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	const auto addOption = [&](LangKey key, Types types) { |  | ||||||
| 		const auto checkbox = content->add( |  | ||||||
| 			object_ptr<Ui::Checkbox>( |  | ||||||
| 				content, |  | ||||||
| 				lang(key), |  | ||||||
| 				((_data.types & types) == types), |  | ||||||
| 				st::defaultBoxCheckbox), |  | ||||||
| 			st::exportSettingPadding); |  | ||||||
| 		base::ObservableViewer( |  | ||||||
| 			checkbox->checkedChanged |  | ||||||
| 		) | rpl::start_with_next([=](bool checked) { |  | ||||||
| 			if (checked) { |  | ||||||
| 				_data.types |= types; |  | ||||||
| 			} else { |  | ||||||
| 				_data.types &= ~types; |  | ||||||
| 			} |  | ||||||
| 			_dataTypesChanges.fire_copy(_data.types); |  | ||||||
| 			refreshButtonsCallback(); |  | ||||||
| 		}, lifetime()); |  | ||||||
| 		return checkbox; |  | ||||||
| 	}; |  | ||||||
| 	const auto addBigOption = [&](LangKey key, Types types) { |  | ||||||
| 		const auto checkbox = addOption(key, types); |  | ||||||
| 		const auto onlyMy = content->add( |  | ||||||
| 			object_ptr<Ui::SlideWrap<Ui::Checkbox>>( |  | ||||||
| 				content, |  | ||||||
| 				object_ptr<Ui::Checkbox>( |  | ||||||
| 					content, |  | ||||||
| 					lang(lng_export_option_only_my), |  | ||||||
| 					((_data.fullChats & types) != types), |  | ||||||
| 					st::defaultBoxCheckbox), |  | ||||||
| 				st::exportSubSettingPadding)); |  | ||||||
| 
 |  | ||||||
| 		base::ObservableViewer( |  | ||||||
| 			onlyMy->entity()->checkedChanged |  | ||||||
| 		) | rpl::start_with_next([=](bool checked) { |  | ||||||
| 			if (checked) { |  | ||||||
| 				_data.fullChats &= ~types; |  | ||||||
| 			} else { |  | ||||||
| 				_data.fullChats |= types; |  | ||||||
| 			} |  | ||||||
| 		}, checkbox->lifetime()); |  | ||||||
| 
 |  | ||||||
| 		onlyMy->toggleOn(base::ObservableViewer( |  | ||||||
| 			checkbox->checkedChanged |  | ||||||
| 		)); |  | ||||||
| 
 |  | ||||||
| 		onlyMy->toggle(checkbox->checked(), anim::type::instant); |  | ||||||
| 
 |  | ||||||
| 		if (types & (Type::PublicGroups | Type::PublicChannels)) { |  | ||||||
| 			onlyMy->entity()->setChecked(true); |  | ||||||
| 			onlyMy->entity()->setDisabled(true); |  | ||||||
| 		} |  | ||||||
| 	}; |  | ||||||
| 	addOption(lng_export_option_info, Type::PersonalInfo | Type::Userpics); |  | ||||||
| 	addOption(lng_export_option_contacts, Type::Contacts); |  | ||||||
| 	addOption(lng_export_option_sessions, Type::Sessions); |  | ||||||
| 	addHeader(content, lng_export_header_chats); |  | ||||||
| 	addOption(lng_export_option_personal_chats, Type::PersonalChats); |  | ||||||
| 	addOption(lng_export_option_bot_chats, Type::BotChats); |  | ||||||
| 	addBigOption(lng_export_option_private_groups, Type::PrivateGroups); |  | ||||||
| 	addBigOption(lng_export_option_private_channels, Type::PrivateChannels); |  | ||||||
| 	addBigOption(lng_export_option_public_groups, Type::PublicGroups); |  | ||||||
| 	addBigOption(lng_export_option_public_channels, Type::PublicChannels); |  | ||||||
| 	const auto mediaWrap = content->add( |  | ||||||
| 		object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>( |  | ||||||
| 			content, |  | ||||||
| 			object_ptr<Ui::VerticalLayout>(content))); |  | ||||||
| 	const auto media = mediaWrap->entity(); |  | ||||||
| 	const auto addSubOption = [&](LangKey key, MediaType type) { |  | ||||||
| 		const auto checkbox = media->add( |  | ||||||
| 			object_ptr<Ui::Checkbox>( |  | ||||||
| 				media, |  | ||||||
| 				lang(key), |  | ||||||
| 				((_data.media.types & type) == type), |  | ||||||
| 				st::defaultBoxCheckbox), |  | ||||||
| 			st::exportSettingPadding); |  | ||||||
| 		base::ObservableViewer( |  | ||||||
| 			checkbox->checkedChanged |  | ||||||
| 		) | rpl::start_with_next([=](bool checked) { |  | ||||||
| 			if (checked) { |  | ||||||
| 				_data.media.types |= type; |  | ||||||
| 			} else { |  | ||||||
| 				_data.media.types &= ~type; |  | ||||||
| 			} |  | ||||||
| 			refreshButtonsCallback(); |  | ||||||
| 		}, lifetime()); |  | ||||||
| 	}; |  | ||||||
| 	addHeader(media, lng_export_header_media); |  | ||||||
| 	addSubOption(lng_export_option_photos, MediaType::Photo); |  | ||||||
| 	addSubOption(lng_export_option_video_files, MediaType::Video); |  | ||||||
| 	addSubOption(lng_export_option_voice_messages, MediaType::VoiceMessage); |  | ||||||
| 	addSubOption(lng_export_option_video_messages, MediaType::VideoMessage); |  | ||||||
| 	addSubOption(lng_export_option_stickers, MediaType::Sticker); |  | ||||||
| 	addSubOption(lng_export_option_gifs, MediaType::GIF); |  | ||||||
| 	addSubOption(lng_export_option_files, MediaType::File); |  | ||||||
| 	createSizeSlider(media); |  | ||||||
| 
 |  | ||||||
| 	const auto formatGroup = std::make_shared<Ui::RadioenumGroup<Format>>( |  | ||||||
| 		_data.format); |  | ||||||
| 	formatGroup->setChangedCallback([=](Format format) { |  | ||||||
| 		_data.format = format; |  | ||||||
| 	}); |  | ||||||
| 	const auto addFormatOption = [&](LangKey key, Format format) { |  | ||||||
| 		const auto radio = content->add( |  | ||||||
| 			object_ptr<Ui::Radioenum<Format>>( |  | ||||||
| 				content, |  | ||||||
| 				formatGroup, |  | ||||||
| 				format, |  | ||||||
| 				lang(key), |  | ||||||
| 				st::defaultBoxCheckbox), |  | ||||||
| 			st::exportSettingPadding); |  | ||||||
| 	}; |  | ||||||
| 	addHeader(content, lng_export_header_format); |  | ||||||
| 	addFormatOption(lng_export_option_text, Format::Text); |  | ||||||
| 	addFormatOption(lng_export_option_json, Format::Json); |  | ||||||
| 
 |  | ||||||
| 	_dataTypesChanges.events_starting_with_copy( |  | ||||||
| 		_data.types |  | ||||||
| 	) | rpl::start_with_next([=](Settings::Types types) { |  | ||||||
| 		mediaWrap->toggle((types & (Type::PersonalChats |  | ||||||
| 			| Type::BotChats |  | ||||||
| 			| Type::PrivateGroups |  | ||||||
| 			| Type::PrivateChannels |  | ||||||
| 			| Type::PublicGroups |  | ||||||
| 			| Type::PublicChannels)) != 0, anim::type::normal); |  | ||||||
| 	}, mediaWrap->lifetime()); |  | ||||||
| 
 |  | ||||||
| 	refreshButtonsCallback(); |  | ||||||
| 
 |  | ||||||
| 	topShadow->raise(); |  | ||||||
| 	bottomShadow->raise(); |  | ||||||
| 
 | 
 | ||||||
| 	sizeValue( | 	sizeValue( | ||||||
| 	) | rpl::start_with_next([=](QSize size) { | 	) | rpl::start_with_next([=](QSize size) { | ||||||
| 		scroll->resize(size.width(), size.height() - buttons->height()); |  | ||||||
| 		wrap->resizeToWidth(size.width()); |  | ||||||
| 		content->resizeToWidth(size.width()); |  | ||||||
| 		buttons->resizeToWidth(size.width()); | 		buttons->resizeToWidth(size.width()); | ||||||
|  | 		buttons->moveToLeft(0, size.height() - buttons->height()); | ||||||
| 		topShadow->resizeToWidth(size.width()); | 		topShadow->resizeToWidth(size.width()); | ||||||
| 		mediaWrap->resizeToWidth(size.width()); |  | ||||||
| 		topShadow->moveToLeft(0, 0); | 		topShadow->moveToLeft(0, 0); | ||||||
| 		bottomShadow->resizeToWidth(size.width()); | 		bottomShadow->resizeToWidth(size.width()); | ||||||
| 		bottomShadow->moveToLeft(0, scroll->height() - st::lineWidth); | 		bottomShadow->moveToLeft(0, buttons->y() - st::lineWidth); | ||||||
| 		buttons->moveToLeft(0, size.height() - buttons->height()); | 	}, buttons->lifetime()); | ||||||
|  | 
 | ||||||
|  | 	return buttons; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SettingsWidget::addHeader( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container, | ||||||
|  | 		LangKey key) { | ||||||
|  | 	container->add( | ||||||
|  | 		object_ptr<Ui::FlatLabel>( | ||||||
|  | 			container, | ||||||
|  | 			lang(key), | ||||||
|  | 			Ui::FlatLabel::InitType::Simple, | ||||||
|  | 			st::exportHeaderLabel), | ||||||
|  | 		st::exportHeaderPadding); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | not_null<Ui::Checkbox*> SettingsWidget::addOption( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container, | ||||||
|  | 		LangKey key, | ||||||
|  | 		Types types) { | ||||||
|  | 	const auto checkbox = container->add( | ||||||
|  | 		object_ptr<Ui::Checkbox>( | ||||||
|  | 			container, | ||||||
|  | 			lang(key), | ||||||
|  | 			((_data.types & types) == types), | ||||||
|  | 			st::defaultBoxCheckbox), | ||||||
|  | 		st::exportSettingPadding); | ||||||
|  | 	base::ObservableViewer( | ||||||
|  | 		checkbox->checkedChanged | ||||||
|  | 	) | rpl::start_with_next([=](bool checked) { | ||||||
|  | 		if (checked) { | ||||||
|  | 			_data.types |= types; | ||||||
|  | 		} else { | ||||||
|  | 			_data.types &= ~types; | ||||||
|  | 		} | ||||||
|  | 		_dataTypesChanges.fire_copy(_data.types); | ||||||
|  | 		_refreshButtons.fire({}); | ||||||
|  | 	}, lifetime()); | ||||||
|  | 	return checkbox; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SettingsWidget::addChatOption( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container, | ||||||
|  | 		LangKey key, | ||||||
|  | 		Types types) { | ||||||
|  | 	const auto checkbox = addOption(container, key, types); | ||||||
|  | 	const auto onlyMy = container->add( | ||||||
|  | 		object_ptr<Ui::SlideWrap<Ui::Checkbox>>( | ||||||
|  | 			container, | ||||||
|  | 			object_ptr<Ui::Checkbox>( | ||||||
|  | 				container, | ||||||
|  | 				lang(lng_export_option_only_my), | ||||||
|  | 				((_data.fullChats & types) != types), | ||||||
|  | 				st::defaultBoxCheckbox), | ||||||
|  | 			st::exportSubSettingPadding)); | ||||||
|  | 
 | ||||||
|  | 	base::ObservableViewer( | ||||||
|  | 		onlyMy->entity()->checkedChanged | ||||||
|  | 	) | rpl::start_with_next([=](bool checked) { | ||||||
|  | 		if (checked) { | ||||||
|  | 			_data.fullChats &= ~types; | ||||||
|  | 		} else { | ||||||
|  | 			_data.fullChats |= types; | ||||||
|  | 		} | ||||||
|  | 	}, checkbox->lifetime()); | ||||||
|  | 
 | ||||||
|  | 	onlyMy->toggleOn(base::ObservableViewer( | ||||||
|  | 		checkbox->checkedChanged | ||||||
|  | 	)); | ||||||
|  | 
 | ||||||
|  | 	onlyMy->toggle(checkbox->checked(), anim::type::instant); | ||||||
|  | 
 | ||||||
|  | 	if (types & (Type::PublicGroups | Type::PublicChannels)) { | ||||||
|  | 		onlyMy->entity()->setChecked(true); | ||||||
|  | 		onlyMy->entity()->setDisabled(true); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SettingsWidget::addMediaOption( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container, | ||||||
|  | 		LangKey key, | ||||||
|  | 		MediaType type) { | ||||||
|  | 	const auto checkbox = container->add( | ||||||
|  | 		object_ptr<Ui::Checkbox>( | ||||||
|  | 			container, | ||||||
|  | 			lang(key), | ||||||
|  | 			((_data.media.types & type) == type), | ||||||
|  | 			st::defaultBoxCheckbox), | ||||||
|  | 		st::exportSettingPadding); | ||||||
|  | 	base::ObservableViewer( | ||||||
|  | 		checkbox->checkedChanged | ||||||
|  | 	) | rpl::start_with_next([=](bool checked) { | ||||||
|  | 		if (checked) { | ||||||
|  | 			_data.media.types |= type; | ||||||
|  | 		} else { | ||||||
|  | 			_data.media.types &= ~type; | ||||||
|  | 		} | ||||||
|  | 		_refreshButtons.fire({}); | ||||||
| 	}, lifetime()); | 	}, lifetime()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SettingsWidget::createSizeSlider( | void SettingsWidget::addSizeSlider( | ||||||
| 		not_null<Ui::VerticalLayout*> container) { | 		not_null<Ui::VerticalLayout*> container) { | ||||||
| 	using namespace rpl::mappers; | 	using namespace rpl::mappers; | ||||||
| 
 | 
 | ||||||
|  | @ -273,7 +362,6 @@ void SettingsWidget::createSizeSlider( | ||||||
| 		st::exportFileSizePadding); | 		st::exportFileSizePadding); | ||||||
| 	slider->resize(st::exportFileSizeSlider.seekSize); | 	slider->resize(st::exportFileSizeSlider.seekSize); | ||||||
| 	slider->setAlwaysDisplayMarker(true); | 	slider->setAlwaysDisplayMarker(true); | ||||||
| 	slider->setMoveByWheel(true); |  | ||||||
| 	slider->setDirection(Ui::ContinuousSlider::Direction::Horizontal); | 	slider->setDirection(Ui::ContinuousSlider::Direction::Horizontal); | ||||||
| 	for (auto i = 0; i != kSizeValueCount + 1; ++i) { | 	for (auto i = 0; i != kSizeValueCount + 1; ++i) { | ||||||
| 		if (_data.media.sizeLimit <= SizeLimitByIndex(i)) { | 		if (_data.media.sizeLimit <= SizeLimitByIndex(i)) { | ||||||
|  | @ -332,7 +420,9 @@ void SettingsWidget::refreshButtons(not_null<Ui::RpWidget*> container) { | ||||||
| 		: nullptr; | 		: nullptr; | ||||||
| 	if (start) { | 	if (start) { | ||||||
| 		start->show(); | 		start->show(); | ||||||
| 		start->addClickHandler([=] { chooseFolder(); }); | 		start->addClickHandler([=] { | ||||||
|  | 			_startClicks.fire(base::duplicate(_data)); | ||||||
|  | 		}); | ||||||
| 
 | 
 | ||||||
| 		container->sizeValue( | 		container->sizeValue( | ||||||
| 		) | rpl::start_with_next([=](QSize size) { | 		) | rpl::start_with_next([=](QSize size) { | ||||||
|  | @ -363,7 +453,7 @@ void SettingsWidget::refreshButtons(not_null<Ui::RpWidget*> container) { | ||||||
| void SettingsWidget::chooseFolder() { | void SettingsWidget::chooseFolder() { | ||||||
| 	const auto ready = [=](QString &&result) { | 	const auto ready = [=](QString &&result) { | ||||||
| 		_data.path = result; | 		_data.path = result; | ||||||
| 		_startClicks.fire(base::duplicate(_data)); | 		_locationChanges.fire(std::move(result)); | ||||||
| 	}; | 	}; | ||||||
| 	FileDialog::GetFolder(this, lang(lng_export_folder), _data.path, ready); | 	FileDialog::GetFolder(this, lang(lng_export_folder), _data.path, ready); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -10,8 +10,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include "export/export_settings.h" | #include "export/export_settings.h" | ||||||
| #include "ui/rp_widget.h" | #include "ui/rp_widget.h" | ||||||
| 
 | 
 | ||||||
|  | enum LangKey : int; | ||||||
|  | 
 | ||||||
| namespace Ui { | namespace Ui { | ||||||
| class VerticalLayout; | class VerticalLayout; | ||||||
|  | class Checkbox; | ||||||
|  | class ScrollArea; | ||||||
| } // namespace Ui
 | } // namespace Ui
 | ||||||
| 
 | 
 | ||||||
| namespace Export { | namespace Export { | ||||||
|  | @ -32,9 +36,32 @@ private: | ||||||
| 	using Format = Output::Format; | 	using Format = Output::Format; | ||||||
| 
 | 
 | ||||||
| 	void setupContent(); | 	void setupContent(); | ||||||
|  | 	not_null<Ui::RpWidget*> setupButtons( | ||||||
|  | 		not_null<Ui::ScrollArea*> scroll, | ||||||
|  | 		not_null<Ui::RpWidget*> wrap); | ||||||
|  | 	void setupOptions(not_null<Ui::VerticalLayout*> container); | ||||||
|  | 	void setupMediaOptions(not_null<Ui::VerticalLayout*> container); | ||||||
|  | 	void setupPathAndFormat(not_null<Ui::VerticalLayout*> container); | ||||||
|  | 	void addHeader( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container, | ||||||
|  | 		LangKey key); | ||||||
|  | 	not_null<Ui::Checkbox*> addOption( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container, | ||||||
|  | 		LangKey key, | ||||||
|  | 		Types types); | ||||||
|  | 	void addChatOption( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container, | ||||||
|  | 		LangKey key, | ||||||
|  | 		Types types); | ||||||
|  | 	void addMediaOption( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container, | ||||||
|  | 		LangKey key, | ||||||
|  | 		MediaType type); | ||||||
|  | 	void addSizeSlider(not_null<Ui::VerticalLayout*> container); | ||||||
|  | 	void addLocationLabel( | ||||||
|  | 		not_null<Ui::VerticalLayout*> container); | ||||||
| 	void chooseFolder(); | 	void chooseFolder(); | ||||||
| 	void refreshButtons(not_null<Ui::RpWidget*> container); | 	void refreshButtons(not_null<Ui::RpWidget*> container); | ||||||
| 	void createSizeSlider(not_null<Ui::VerticalLayout*> container); |  | ||||||
| 
 | 
 | ||||||
| 	Settings _data; | 	Settings _data; | ||||||
| 	struct Wrap { | 	struct Wrap { | ||||||
|  | @ -43,11 +70,12 @@ private: | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		rpl::producer<> value; | 		rpl::producer<> value; | ||||||
| 
 |  | ||||||
| 	}; | 	}; | ||||||
| 	rpl::event_stream<Settings> _startClicks; | 	rpl::event_stream<Settings> _startClicks; | ||||||
| 	rpl::variable<Wrap> _cancelClicks; | 	rpl::variable<Wrap> _cancelClicks; | ||||||
| 	rpl::event_stream<Settings::Types> _dataTypesChanges; | 	rpl::event_stream<Settings::Types> _dataTypesChanges; | ||||||
|  | 	rpl::event_stream<> _refreshButtons; | ||||||
|  | 	rpl::event_stream<QString> _locationChanges; | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -271,7 +271,7 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() { | ||||||
| 			lng_info_link_label, | 			lng_info_link_label, | ||||||
| 			std::move(linkText), | 			std::move(linkText), | ||||||
| 			QString()); | 			QString()); | ||||||
| 		link->setClickHandlerHook([peer = _peer](auto&&...) { | 		link->setClickHandlerFilter([peer = _peer](auto&&...) { | ||||||
| 			auto link = Messenger::Instance().createInternalLinkFull( | 			auto link = Messenger::Instance().createInternalLinkFull( | ||||||
| 				peer->userName()); | 				peer->userName()); | ||||||
| 			if (!link.isEmpty()) { | 			if (!link.isEmpty()) { | ||||||
|  |  | ||||||
|  | @ -331,7 +331,7 @@ void GroupMembersWidget::refreshLimitReached() { | ||||||
| 		QString link = TextUtilities::EscapeForRichParsing(lang(lng_profile_migrate_learn_more)); | 		QString link = TextUtilities::EscapeForRichParsing(lang(lng_profile_migrate_learn_more)); | ||||||
| 		QString text = qsl("%1%2%3\n%4 [a href=\"https://telegram.org/blog/supergroups5k\"]%5[/a]").arg(textcmdStartSemibold()).arg(title).arg(textcmdStopSemibold()).arg(body).arg(link); | 		QString text = qsl("%1%2%3\n%4 [a href=\"https://telegram.org/blog/supergroups5k\"]%5[/a]").arg(textcmdStartSemibold()).arg(title).arg(textcmdStopSemibold()).arg(body).arg(link); | ||||||
| 		_limitReachedInfo->setRichText(text); | 		_limitReachedInfo->setRichText(text); | ||||||
| 		_limitReachedInfo->setClickHandlerHook([this](const ClickHandlerPtr &handler, Qt::MouseButton button) { | 		_limitReachedInfo->setClickHandlerFilter([=](auto&&...) { | ||||||
| 			Ui::show(Box<ConvertToSupergroupBox>(peer()->asChat())); | 			Ui::show(Box<ConvertToSupergroupBox>(peer()->asChat())); | ||||||
| 			return false; | 			return false; | ||||||
| 		}); | 		}); | ||||||
|  |  | ||||||
|  | @ -88,7 +88,7 @@ void InfoWidget::refreshUsername() { | ||||||
| 		TextWithEntities(), | 		TextWithEntities(), | ||||||
| 		copyText); | 		copyText); | ||||||
| 	if (auto text = _username->entity()->textLabel()) { | 	if (auto text = _username->entity()->textLabel()) { | ||||||
| 		text->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) { | 		text->setClickHandlerFilter([](auto&&...) { | ||||||
| 			Ui::show(Box<UsernameBox>()); | 			Ui::show(Box<UsernameBox>()); | ||||||
| 			return false; | 			return false; | ||||||
| 		}); | 		}); | ||||||
|  | @ -115,7 +115,7 @@ void InfoWidget::refreshBio() { | ||||||
| 		TextWithEntities(), | 		TextWithEntities(), | ||||||
| 		QString()); | 		QString()); | ||||||
| 	if (auto text = _bio->entity()->textLabel()) { | 	if (auto text = _bio->entity()->textLabel()) { | ||||||
| 		text->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) { | 		text->setClickHandlerFilter([](auto&&...) { | ||||||
| 			Ui::show(Box<EditBioBox>(App::self())); | 			Ui::show(Box<EditBioBox>(App::self())); | ||||||
| 			return false; | 			return false; | ||||||
| 		}); | 		}); | ||||||
|  |  | ||||||
|  | @ -272,8 +272,8 @@ void FlatLabel::setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk) { | ||||||
| 	_text.setLink(lnkIndex, lnk); | 	_text.setLink(lnkIndex, lnk); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FlatLabel::setClickHandlerHook(ClickHandlerHook &&hook) { | void FlatLabel::setClickHandlerFilter(ClickHandlerFilter &&filter) { | ||||||
| 	_clickHandlerHook = std::move(hook); | 	_clickHandlerFilter = std::move(filter); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FlatLabel::mouseMoveEvent(QMouseEvent *e) { | void FlatLabel::mouseMoveEvent(QMouseEvent *e) { | ||||||
|  | @ -358,7 +358,8 @@ Text::StateResult FlatLabel::dragActionFinish(const QPoint &p, Qt::MouseButton b | ||||||
| 	_selectionType = TextSelectType::Letters; | 	_selectionType = TextSelectType::Letters; | ||||||
| 
 | 
 | ||||||
| 	if (activated) { | 	if (activated) { | ||||||
| 		if (!_clickHandlerHook || _clickHandlerHook(activated, button)) { | 		if (!_clickHandlerFilter | ||||||
|  | 			|| _clickHandlerFilter(activated, button)) { | ||||||
| 			App::activateClickHandler(activated, button); | 			App::activateClickHandler(activated, button); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -112,8 +112,8 @@ public: | ||||||
| 
 | 
 | ||||||
| 	void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk); | 	void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk); | ||||||
| 
 | 
 | ||||||
| 	using ClickHandlerHook = Fn<bool(const ClickHandlerPtr&, Qt::MouseButton)>; | 	using ClickHandlerFilter = Fn<bool(const ClickHandlerPtr&, Qt::MouseButton)>; | ||||||
| 	void setClickHandlerHook(ClickHandlerHook &&hook); | 	void setClickHandlerFilter(ClickHandlerFilter &&filter); | ||||||
| 
 | 
 | ||||||
| 	// ClickHandlerHost interface
 | 	// ClickHandlerHost interface
 | ||||||
| 	void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override; | 	void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override; | ||||||
|  | @ -207,7 +207,7 @@ private: | ||||||
| 	QString _contextCopyText; | 	QString _contextCopyText; | ||||||
| 	ExpandLinksMode _contextExpandLinksMode = ExpandLinksAll; | 	ExpandLinksMode _contextExpandLinksMode = ExpandLinksAll; | ||||||
| 
 | 
 | ||||||
| 	ClickHandlerHook _clickHandlerHook; | 	ClickHandlerFilter _clickHandlerFilter; | ||||||
| 
 | 
 | ||||||
| 	// text selection and context menu by touch support (at least Windows Surface tablets)
 | 	// text selection and context menu by touch support (at least Windows Surface tablets)
 | ||||||
| 	bool _touchSelect = false; | 	bool _touchSelect = false; | ||||||
|  |  | ||||||
|  | @ -243,7 +243,7 @@ void TermsBox::prepare() { | ||||||
| 			st::termsPadding), | 			st::termsPadding), | ||||||
| 		0, | 		0, | ||||||
| 		age ? age->height() : 0); | 		age ? age->height() : 0); | ||||||
| 	content->entity()->setClickHandlerHook([=]( | 	content->entity()->setClickHandlerFilter([=]( | ||||||
| 			const ClickHandlerPtr &handler, | 			const ClickHandlerPtr &handler, | ||||||
| 			Qt::MouseButton button) { | 			Qt::MouseButton button) { | ||||||
| 		const auto link = handler | 		const auto link = handler | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 John Preston
						John Preston