mirror of https://github.com/procxx/kepka.git
				
				
				
			Cross-fade login QR.
This commit is contained in:
		
							parent
							
								
									f4bf79b067
								
							
						
					
					
						commit
						a0152557ec
					
				|  | @ -174,6 +174,7 @@ introQrTitle: FlatLabel(defaultFlatLabel) { | ||||||
| 		linkFontOver: font(20px semibold underline); | 		linkFontOver: font(20px semibold underline); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | introQrErrorTop: 336px; | ||||||
| introQrTitleTop: 196px; | introQrTitleTop: 196px; | ||||||
| introQrStep: defaultFlatLabel; | introQrStep: defaultFlatLabel; | ||||||
| introQrStepsTop: 232px; | introQrStepsTop: 232px; | ||||||
|  |  | ||||||
|  | @ -56,7 +56,14 @@ namespace { | ||||||
| 	if (max > 0 && data.size * pixel > max) { | 	if (max > 0 && data.size * pixel > max) { | ||||||
| 		pixel = std::max(max / data.size, 1); | 		pixel = std::max(max / data.size, 1); | ||||||
| 	} | 	} | ||||||
| 	return TelegramQrExact(data, pixel * style::DevicePixelRatio()); | 	const auto qr = TelegramQrExact(data, pixel * style::DevicePixelRatio()); | ||||||
|  | 	auto result = QImage(qr.size(), QImage::Format_ARGB32_Premultiplied); | ||||||
|  | 	result.fill(st::windowBg->c); | ||||||
|  | 	{ | ||||||
|  | 		auto p = QPainter(&result); | ||||||
|  | 		p.drawImage(QRect(QPoint(), qr.size()), qr); | ||||||
|  | 	} | ||||||
|  | 	return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [[nodiscard]] not_null<Ui::RpWidget*> PrepareQrWidget( | [[nodiscard]] not_null<Ui::RpWidget*> PrepareQrWidget( | ||||||
|  | @ -67,8 +74,10 @@ namespace { | ||||||
| 		: waiting(callback, st::defaultInfiniteRadialAnimation) { | 		: waiting(callback, st::defaultInfiniteRadialAnimation) { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		QImage previous; | ||||||
| 		QImage qr; | 		QImage qr; | ||||||
| 		QImage center; | 		QImage center; | ||||||
|  | 		Ui::Animations::Simple shown; | ||||||
| 		Ui::InfiniteRadialAnimation waiting; | 		Ui::InfiniteRadialAnimation waiting; | ||||||
| 	}; | 	}; | ||||||
| 	auto qrs = std::move( | 	auto qrs = std::move( | ||||||
|  | @ -92,9 +101,15 @@ namespace { | ||||||
| 	) | rpl::map([](const Qr::Data &code, const auto &) { | 	) | rpl::map([](const Qr::Data &code, const auto &) { | ||||||
| 		return TelegramQr(code, st::introQrPixel, st::introQrMaxSize); | 		return TelegramQr(code, st::introQrPixel, st::introQrMaxSize); | ||||||
| 	}) | rpl::start_with_next([=](QImage &&image) { | 	}) | rpl::start_with_next([=](QImage &&image) { | ||||||
|  | 		state->previous = std::move(state->qr); | ||||||
| 		state->qr = std::move(image); | 		state->qr = std::move(image); | ||||||
| 		state->waiting.stop(); | 		state->waiting.stop(); | ||||||
| 		result->update(); | 		state->shown.stop(); | ||||||
|  | 		state->shown.start( | ||||||
|  | 			[=] { result->update(); }, | ||||||
|  | 			0., | ||||||
|  | 			1., | ||||||
|  | 			st::fadeWrapDuration); | ||||||
| 	}, result->lifetime()); | 	}, result->lifetime()); | ||||||
| 	std::move( | 	std::move( | ||||||
| 		palettes | 		palettes | ||||||
|  | @ -106,7 +121,24 @@ namespace { | ||||||
| 	result->paintRequest( | 	result->paintRequest( | ||||||
| 	) | rpl::start_with_next([=](QRect clip) { | 	) | rpl::start_with_next([=](QRect clip) { | ||||||
| 		auto p = QPainter(result); | 		auto p = QPainter(result); | ||||||
| 		auto rect = QRect( | 		const auto shown = state->qr.isNull() ? 0. : state->shown.value(1.); | ||||||
|  | 		if (!state->qr.isNull()) { | ||||||
|  | 			const auto size = state->qr.size() / cIntRetinaFactor(); | ||||||
|  | 			const auto qr = QRect( | ||||||
|  | 				(result->width() - size.width()) / 2, | ||||||
|  | 				(result->height() - size.height()) / 2, | ||||||
|  | 				size.width(), | ||||||
|  | 				size.height()); | ||||||
|  | 			if (shown == 1.) { | ||||||
|  | 				state->previous = QImage(); | ||||||
|  | 			} else if (!state->previous.isNull()) { | ||||||
|  | 				p.drawImage(qr, state->previous); | ||||||
|  | 			} | ||||||
|  | 			p.setOpacity(shown); | ||||||
|  | 			p.drawImage(qr, state->qr); | ||||||
|  | 			p.setOpacity(1.); | ||||||
|  | 		} | ||||||
|  | 		const auto rect = QRect( | ||||||
| 			(result->width() - st::introQrCenterSize) / 2, | 			(result->width() - st::introQrCenterSize) / 2, | ||||||
| 			(result->height() - st::introQrCenterSize) / 2, | 			(result->height() - st::introQrCenterSize) / 2, | ||||||
| 			st::introQrCenterSize, | 			st::introQrCenterSize, | ||||||
|  | @ -119,7 +151,7 @@ namespace { | ||||||
| 			auto pen = st::activeButtonBg->p; | 			auto pen = st::activeButtonBg->p; | ||||||
| 			pen.setWidth(line); | 			pen.setWidth(line); | ||||||
| 			pen.setCapStyle(Qt::RoundCap); | 			pen.setCapStyle(Qt::RoundCap); | ||||||
| 			p.setOpacity(radial.shown); | 			p.setOpacity(radial.shown * (1. - shown)); | ||||||
| 			p.setPen(pen); | 			p.setPen(pen); | ||||||
| 			p.drawArc( | 			p.drawArc( | ||||||
| 				rect.marginsAdded({ line, line, line, line }), | 				rect.marginsAdded({ line, line, line, line }), | ||||||
|  | @ -127,16 +159,6 @@ namespace { | ||||||
| 				radial.arcLength); | 				radial.arcLength); | ||||||
| 			p.setOpacity(1.); | 			p.setOpacity(1.); | ||||||
| 		} | 		} | ||||||
| 		if (!state->qr.isNull()) { |  | ||||||
| 			const auto size = state->qr.size() / cIntRetinaFactor(); |  | ||||||
| 			p.drawImage( |  | ||||||
| 				QRect( |  | ||||||
| 					(result->width() - size.width()) / 2, |  | ||||||
| 					(result->height() - size.height()) / 2, |  | ||||||
| 					size.width(), |  | ||||||
| 					size.height()), |  | ||||||
| 				state->qr); |  | ||||||
| 		} |  | ||||||
| 	}, result->lifetime()); | 	}, result->lifetime()); | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  | @ -148,7 +170,7 @@ QrWidget::QrWidget( | ||||||
| 	not_null<Main::Account*> account, | 	not_null<Main::Account*> account, | ||||||
| 	not_null<Data*> data) | 	not_null<Data*> data) | ||||||
| : Step(parent, account, data) | : Step(parent, account, data) | ||||||
| 	, _refreshTimer([=] { refreshCode(); }) { | , _refreshTimer([=] { refreshCode(); }) { | ||||||
| 	setTitleText(rpl::single(QString())); | 	setTitleText(rpl::single(QString())); | ||||||
| 	setDescriptionText(rpl::single(QString())); | 	setDescriptionText(rpl::single(QString())); | ||||||
| 	setErrorCentered(true); | 	setErrorCentered(true); | ||||||
|  | @ -163,6 +185,10 @@ QrWidget::QrWidget( | ||||||
| 	refreshCode(); | 	refreshCode(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int QrWidget::errorTop() const { | ||||||
|  | 	return contentTop() + st::introQrErrorTop; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void QrWidget::checkForTokenUpdate(const MTPUpdates &updates) { | void QrWidget::checkForTokenUpdate(const MTPUpdates &updates) { | ||||||
| 	updates.match([&](const MTPDupdateShort &data) { | 	updates.match([&](const MTPDupdateShort &data) { | ||||||
| 		checkForTokenUpdate(data.vupdate()); | 		checkForTokenUpdate(data.vupdate()); | ||||||
|  | @ -256,9 +282,7 @@ void QrWidget::setupControls() { | ||||||
| 			contentTop() + st::introQrSkipTop); | 			contentTop() + st::introQrSkipTop); | ||||||
| 	}, skip->lifetime()); | 	}, skip->lifetime()); | ||||||
| 
 | 
 | ||||||
| 	skip->setClickedCallback([=] { | 	skip->setClickedCallback([=] { submit(); }); | ||||||
| 		goNext<PhoneWidget>(); |  | ||||||
| 	}); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void QrWidget::refreshCode() { | void QrWidget::refreshCode() { | ||||||
|  |  | ||||||
|  | @ -40,6 +40,8 @@ public: | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | 	int errorTop() const override; | ||||||
|  | 
 | ||||||
| 	void setupControls(); | 	void setupControls(); | ||||||
| 	void refreshCode(); | 	void refreshCode(); | ||||||
| 	void checkForTokenUpdate(const MTPUpdates &updates); | 	void checkForTokenUpdate(const MTPUpdates &updates); | ||||||
|  |  | ||||||
|  | @ -179,11 +179,14 @@ void Step::updateLabelsPosition() { | ||||||
| 		} | 		} | ||||||
| 		Ui::SendPendingMoveResizeEvents(_error->entity()); | 		Ui::SendPendingMoveResizeEvents(_error->entity()); | ||||||
| 		auto errorLeft = _errorCentered ? 0 : (contentLeft() + st::buttonRadius); | 		auto errorLeft = _errorCentered ? 0 : (contentLeft() + st::buttonRadius); | ||||||
| 		auto errorTop = contentTop() + (_errorBelowLink ? st::introErrorBelowLinkTop : st::introErrorTop); | 		_error->moveToLeft(errorLeft, errorTop()); | ||||||
| 		_error->moveToLeft(errorLeft, errorTop); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int Step::errorTop() const { | ||||||
|  | 	return contentTop() + st::introErrorTop; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Step::setTitleText(rpl::producer<QString> titleText) { | void Step::setTitleText(rpl::producer<QString> titleText) { | ||||||
| 	_titleText = std::move(titleText); | 	_titleText = std::move(titleText); | ||||||
| } | } | ||||||
|  | @ -364,13 +367,6 @@ void Step::setErrorCentered(bool centered) { | ||||||
| 	_error.destroy(); | 	_error.destroy(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Step::setErrorBelowLink(bool below) { |  | ||||||
| 	_errorBelowLink = below; |  | ||||||
| 	if (_error) { |  | ||||||
| 		updateLabelsPosition(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Step::showError(rpl::producer<QString> text) { | void Step::showError(rpl::producer<QString> text) { | ||||||
| 	_errorText = std::move(text); | 	_errorText = std::move(text); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -78,7 +78,6 @@ public: | ||||||
| 	[[nodiscard]] int contentTop() const; | 	[[nodiscard]] int contentTop() const; | ||||||
| 
 | 
 | ||||||
| 	void setErrorCentered(bool centered); | 	void setErrorCentered(bool centered); | ||||||
| 	void setErrorBelowLink(bool below); |  | ||||||
| 	void showError(rpl::producer<QString> text); | 	void showError(rpl::producer<QString> text); | ||||||
| 	void hideError() { | 	void hideError() { | ||||||
| 		showError(rpl::single(QString())); | 		showError(rpl::single(QString())); | ||||||
|  | @ -128,6 +127,8 @@ protected: | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	virtual int errorTop() const; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
| 	struct CoverAnimation { | 	struct CoverAnimation { | ||||||
| 		CoverAnimation() = default; | 		CoverAnimation() = default; | ||||||
|  |  | ||||||
|  | @ -95,7 +95,6 @@ CodeWidget::CodeWidget( | ||||||
| 	_noTelegramCode->addClickHandler([=] { onNoTelegramCode(); }); | 	_noTelegramCode->addClickHandler([=] { onNoTelegramCode(); }); | ||||||
| 
 | 
 | ||||||
| 	_code->setDigitsCountMax(getData()->codeLength); | 	_code->setDigitsCountMax(getData()->codeLength); | ||||||
| 	setErrorBelowLink(true); |  | ||||||
| 
 | 
 | ||||||
| 	setTitleText(rpl::single(App::formatPhone(getData()->phone))); | 	setTitleText(rpl::single(App::formatPhone(getData()->phone))); | ||||||
| 	updateDescText(); | 	updateDescText(); | ||||||
|  | @ -107,6 +106,10 @@ void CodeWidget::refreshLang() { | ||||||
| 	updateControlsGeometry(); | 	updateControlsGeometry(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int CodeWidget::errorTop() const { | ||||||
|  | 	return contentTop() + st::introErrorBelowLinkTop; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void CodeWidget::updateDescText() { | void CodeWidget::updateDescText() { | ||||||
| 	const auto byTelegram = getData()->codeByTelegram; | 	const auto byTelegram = getData()->codeByTelegram; | ||||||
| 	setDescriptionText( | 	setDescriptionText( | ||||||
|  |  | ||||||
|  | @ -69,6 +69,8 @@ private slots: | ||||||
| 	void onCheckRequest(); | 	void onCheckRequest(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | 	int errorTop() const override; | ||||||
|  | 
 | ||||||
| 	void updateCallText(); | 	void updateCallText(); | ||||||
| 	void refreshLang(); | 	void refreshLang(); | ||||||
| 	void updateControlsGeometry(); | 	void updateControlsGeometry(); | ||||||
|  |  | ||||||
|  | @ -50,7 +50,6 @@ PwdCheckWidget::PwdCheckWidget( | ||||||
| 
 | 
 | ||||||
| 	setTitleText(tr::lng_signin_title()); | 	setTitleText(tr::lng_signin_title()); | ||||||
| 	updateDescriptionText(); | 	updateDescriptionText(); | ||||||
| 	setErrorBelowLink(true); |  | ||||||
| 
 | 
 | ||||||
| 	if (_hint.isEmpty()) { | 	if (_hint.isEmpty()) { | ||||||
| 		_pwdHint->hide(); | 		_pwdHint->hide(); | ||||||
|  | @ -79,6 +78,10 @@ void PwdCheckWidget::refreshLang() { | ||||||
| 	updateControlsGeometry(); | 	updateControlsGeometry(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int PwdCheckWidget::errorTop() const { | ||||||
|  | 	return contentTop() + st::introErrorBelowLinkTop; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void PwdCheckWidget::resizeEvent(QResizeEvent *e) { | void PwdCheckWidget::resizeEvent(QResizeEvent *e) { | ||||||
| 	Step::resizeEvent(e); | 	Step::resizeEvent(e); | ||||||
| 	updateControlsGeometry(); | 	updateControlsGeometry(); | ||||||
|  |  | ||||||
|  | @ -46,6 +46,8 @@ private slots: | ||||||
| 	void onCheckRequest(); | 	void onCheckRequest(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | 	int errorTop() const override; | ||||||
|  | 
 | ||||||
| 	void showReset(); | 	void showReset(); | ||||||
| 	void refreshLang(); | 	void refreshLang(); | ||||||
| 	void updateControlsGeometry(); | 	void updateControlsGeometry(); | ||||||
|  |  | ||||||
|  | @ -122,7 +122,7 @@ void Widget::createLanguageLink() { | ||||||
| 			Lang::CurrentCloudManager().switchToLanguage(languageId); | 			Lang::CurrentCloudManager().switchToLanguage(languageId); | ||||||
| 		}); | 		}); | ||||||
| 		_changeLanguage->toggle( | 		_changeLanguage->toggle( | ||||||
| 			!_resetAccount && !_terms, | 			!_resetAccount && !_terms && _nextShown, | ||||||
| 			anim::type::normal); | 			anim::type::normal); | ||||||
| 		updateControlsGeometry(); | 		updateControlsGeometry(); | ||||||
| 	}; | 	}; | ||||||
|  | @ -230,11 +230,6 @@ void Widget::historyMove(Direction direction) { | ||||||
| 	setupNextButton(); | 	setupNextButton(); | ||||||
| 	if (_resetAccount) _resetAccount->show(anim::type::normal); | 	if (_resetAccount) _resetAccount->show(anim::type::normal); | ||||||
| 	if (_terms) _terms->show(anim::type::normal); | 	if (_terms) _terms->show(anim::type::normal); | ||||||
| 	if (_changeLanguage) { |  | ||||||
| 		_changeLanguage->toggle( |  | ||||||
| 			!_resetAccount && !_terms, |  | ||||||
| 			anim::type::normal); |  | ||||||
| 	} |  | ||||||
| 	getStep()->showAnimated(direction); | 	getStep()->showAnimated(direction); | ||||||
| 	fixOrder(); | 	fixOrder(); | ||||||
| } | } | ||||||
|  | @ -253,6 +248,7 @@ void Widget::hideAndDestroy(object_ptr<Ui::FadeWrap<Ui::RpWidget>> widget) { | ||||||
| void Widget::fixOrder() { | void Widget::fixOrder() { | ||||||
| 	_next->raise(); | 	_next->raise(); | ||||||
| 	if (_update) _update->raise(); | 	if (_update) _update->raise(); | ||||||
|  | 	if (_changeLanguage) _changeLanguage->raise(); | ||||||
| 	_settings->raise(); | 	_settings->raise(); | ||||||
| 	_back->raise(); | 	_back->raise(); | ||||||
| 	_connecting->raise(); | 	_connecting->raise(); | ||||||
|  | @ -333,7 +329,7 @@ void Widget::showTerms() { | ||||||
| 	} | 	} | ||||||
| 	if (_changeLanguage) { | 	if (_changeLanguage) { | ||||||
| 		_changeLanguage->toggle( | 		_changeLanguage->toggle( | ||||||
| 			!_terms && !_resetAccount, | 			!_terms && !_resetAccount && _nextShown, | ||||||
| 			anim::type::normal); | 			anim::type::normal); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -491,7 +487,7 @@ void Widget::showControls() { | ||||||
| 	} | 	} | ||||||
| 	if (_changeLanguage) { | 	if (_changeLanguage) { | ||||||
| 		_changeLanguage->toggle( | 		_changeLanguage->toggle( | ||||||
| 			!_resetAccount && !_terms, | 			!_resetAccount && !_terms && _nextShown, | ||||||
| 			anim::type::instant); | 			anim::type::instant); | ||||||
| 	} | 	} | ||||||
| 	if (_terms) { | 	if (_terms) { | ||||||
|  | @ -508,12 +504,19 @@ void Widget::setupNextButton() { | ||||||
| 	auto visible = getStep()->nextButtonText( | 	auto visible = getStep()->nextButtonText( | ||||||
| 	) | rpl::map([](const QString &text) { | 	) | rpl::map([](const QString &text) { | ||||||
| 		return !text.isEmpty(); | 		return !text.isEmpty(); | ||||||
| 	}) | rpl::distinct_until_changed(); | 	}); | ||||||
| 	std::move( | 	std::move( | ||||||
| 		visible | 		visible | ||||||
| 	) | rpl::start_with_next([=](bool visible) { | 	) | rpl::filter([=](bool visible) { | ||||||
|  | 		return visible != _nextShown; | ||||||
|  | 	}) | rpl::start_with_next([=](bool visible) { | ||||||
| 		_next->toggle(visible, anim::type::normal); | 		_next->toggle(visible, anim::type::normal); | ||||||
| 		_nextShown = visible; | 		_nextShown = visible; | ||||||
|  | 		if (_changeLanguage) { | ||||||
|  | 			_changeLanguage->toggle( | ||||||
|  | 				!_resetAccount && !_terms && _nextShown, | ||||||
|  | 				anim::type::normal); | ||||||
|  | 		} | ||||||
| 		_nextShownAnimation.start( | 		_nextShownAnimation.start( | ||||||
| 			[=] { updateControlsGeometry(); }, | 			[=] { updateControlsGeometry(); }, | ||||||
| 			_nextShown ? 0. : 1., | 			_nextShown ? 0. : 1., | ||||||
|  |  | ||||||
|  | @ -152,7 +152,7 @@ private: | ||||||
| 
 | 
 | ||||||
| 	std::unique_ptr<Window::ConnectionState> _connecting; | 	std::unique_ptr<Window::ConnectionState> _connecting; | ||||||
| 
 | 
 | ||||||
| 	bool _nextShown = false; | 	bool _nextShown = true; | ||||||
| 	Ui::Animations::Simple _nextShownAnimation; | 	Ui::Animations::Simple _nextShownAnimation; | ||||||
| 
 | 
 | ||||||
| 	mtpRequestId _resetRequest = 0; | 	mtpRequestId _resetRequest = 0; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue