mirror of
https://github.com/telegramdesktop/tdesktop
synced 2024-12-27 09:03:02 +00:00
Add slide animations in CreatePollBox.
This commit is contained in:
parent
6f176803d4
commit
f291e365e5
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "data/data_poll.h"
|
#include "data/data_poll.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/wrap/vertical_layout.h"
|
#include "ui/wrap/vertical_layout.h"
|
||||||
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
@ -56,6 +57,9 @@ private:
|
|||||||
|
|
||||||
void toggleRemoveAlways(bool toggled);
|
void toggleRemoveAlways(bool toggled);
|
||||||
|
|
||||||
|
void show(anim::type animated);
|
||||||
|
void destroy(FnMut<void()> done);
|
||||||
|
|
||||||
//[[nodisacrd]] bool hasShadow() const;
|
//[[nodisacrd]] bool hasShadow() const;
|
||||||
//void destroyShadow();
|
//void destroyShadow();
|
||||||
|
|
||||||
@ -75,6 +79,21 @@ private:
|
|||||||
|
|
||||||
[[nodiscard]] rpl::producer<Qt::MouseButton> removeClicks() const;
|
[[nodiscard]] rpl::producer<Qt::MouseButton> removeClicks() const;
|
||||||
|
|
||||||
|
inline bool operator<(const Option &other) const {
|
||||||
|
return field() < other.field();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend inline bool operator<(
|
||||||
|
const Option &option,
|
||||||
|
Ui::InputField *field) {
|
||||||
|
return option.field() < field;
|
||||||
|
}
|
||||||
|
friend inline bool operator<(
|
||||||
|
Ui::InputField *field,
|
||||||
|
const Option &option) {
|
||||||
|
return field < option.field();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Option() = default;
|
Option() = default;
|
||||||
|
|
||||||
@ -82,7 +101,7 @@ private:
|
|||||||
void createRemove();
|
void createRemove();
|
||||||
void createWarning();
|
void createWarning();
|
||||||
|
|
||||||
base::unique_qptr<Ui::InputField> _field;
|
base::unique_qptr<Ui::SlideWrap<Ui::InputField>> _field;
|
||||||
base::unique_qptr<Ui::PlainShadow> _shadow;
|
base::unique_qptr<Ui::PlainShadow> _shadow;
|
||||||
base::unique_qptr<Ui::CrossButton> _remove;
|
base::unique_qptr<Ui::CrossButton> _remove;
|
||||||
rpl::variable<bool> *_removeAlways = nullptr;
|
rpl::variable<bool> *_removeAlways = nullptr;
|
||||||
@ -97,12 +116,15 @@ private:
|
|||||||
void checkLastOption();
|
void checkLastOption();
|
||||||
void validateState();
|
void validateState();
|
||||||
void fixAfterErase();
|
void fixAfterErase();
|
||||||
|
void destroy(Option &&option);
|
||||||
|
void removeDestroyed(not_null<Ui::InputField*> field);
|
||||||
int findField(not_null<Ui::InputField*> field) const;
|
int findField(not_null<Ui::InputField*> field) const;
|
||||||
|
|
||||||
not_null<QWidget*> _outer;
|
not_null<QWidget*> _outer;
|
||||||
not_null<Ui::VerticalLayout*> _container;
|
not_null<Ui::VerticalLayout*> _container;
|
||||||
int _position = 0;
|
int _position = 0;
|
||||||
std::vector<Option> _list;
|
std::vector<Option> _list;
|
||||||
|
std::set<Option, std::less<>> _destroyed;
|
||||||
rpl::variable<bool> _valid = false;
|
rpl::variable<bool> _valid = false;
|
||||||
rpl::variable<int> _usedCount = 0;
|
rpl::variable<int> _usedCount = 0;
|
||||||
rpl::event_stream<not_null<QWidget*>> _scrollToWidget;
|
rpl::event_stream<not_null<QWidget*>> _scrollToWidget;
|
||||||
@ -157,12 +179,14 @@ Options::Option Options::Option::Create(
|
|||||||
auto result = Option();
|
auto result = Option();
|
||||||
const auto field = container->insert(
|
const auto field = container->insert(
|
||||||
position,
|
position,
|
||||||
object_ptr<Ui::InputField>(
|
object_ptr<Ui::SlideWrap<Ui::InputField>>(
|
||||||
container,
|
container,
|
||||||
st::createPollOptionField,
|
object_ptr<Ui::InputField>(
|
||||||
langFactory(lng_polls_create_option_add)));
|
container,
|
||||||
InitField(outer, field);
|
st::createPollOptionField,
|
||||||
field->setMaxLength(kOptionLimit + kErrorLimit);
|
langFactory(lng_polls_create_option_add))));
|
||||||
|
InitField(outer, field->entity());
|
||||||
|
field->entity()->setMaxLength(kOptionLimit + kErrorLimit);
|
||||||
result._field.reset(field);
|
result._field.reset(field);
|
||||||
|
|
||||||
result.createShadow();
|
result.createShadow();
|
||||||
@ -181,9 +205,9 @@ void Options::Option::createShadow() {
|
|||||||
if (_shadow) {
|
if (_shadow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto value = Ui::CreateChild<Ui::PlainShadow>(_field.get());
|
const auto value = Ui::CreateChild<Ui::PlainShadow>(field().get());
|
||||||
value->show();
|
value->show();
|
||||||
_field->sizeValue(
|
field()->sizeValue(
|
||||||
) | rpl::start_with_next([=](QSize size) {
|
) | rpl::start_with_next([=](QSize size) {
|
||||||
const auto left = st::createPollFieldPadding.left();
|
const auto left = st::createPollFieldPadding.left();
|
||||||
value->setGeometry(
|
value->setGeometry(
|
||||||
@ -202,11 +226,11 @@ void Options::Option::createShadow() {
|
|||||||
void Options::Option::createRemove() {
|
void Options::Option::createRemove() {
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
|
|
||||||
const auto field = _field.get();
|
const auto field = this->field();
|
||||||
auto &lifetime = field->lifetime();
|
auto &lifetime = field->lifetime();
|
||||||
|
|
||||||
const auto remove = Ui::CreateChild<Ui::CrossButton>(
|
const auto remove = Ui::CreateChild<Ui::CrossButton>(
|
||||||
field,
|
field.get(),
|
||||||
st::createPollOptionRemove);
|
st::createPollOptionRemove);
|
||||||
remove->hide(anim::type::instant);
|
remove->hide(anim::type::instant);
|
||||||
|
|
||||||
@ -239,7 +263,7 @@ void Options::Option::createRemove() {
|
|||||||
void Options::Option::createWarning() {
|
void Options::Option::createWarning() {
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
|
|
||||||
const auto field = _field.get();
|
const auto field = this->field();
|
||||||
const auto warning = CreateWarningLabel(
|
const auto warning = CreateWarningLabel(
|
||||||
field,
|
field,
|
||||||
field,
|
field,
|
||||||
@ -261,31 +285,31 @@ void Options::Option::createWarning() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Options::Option::isEmpty() const {
|
bool Options::Option::isEmpty() const {
|
||||||
return _field->getLastText().trimmed().isEmpty();
|
return field()->getLastText().trimmed().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Options::Option::isGood() const {
|
bool Options::Option::isGood() const {
|
||||||
return !_field->getLastText().trimmed().isEmpty() && !isTooLong();
|
return !field()->getLastText().trimmed().isEmpty() && !isTooLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Options::Option::isTooLong() const {
|
bool Options::Option::isTooLong() const {
|
||||||
return (_field->getLastText().size() > kOptionLimit);
|
return (field()->getLastText().size() > kOptionLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Options::Option::hasFocus() const {
|
bool Options::Option::hasFocus() const {
|
||||||
return _field->hasFocus();
|
return field()->hasFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Options::Option::setFocus() const {
|
void Options::Option::setFocus() const {
|
||||||
FocusAtEnd(_field);
|
FocusAtEnd(field());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Options::Option::clearValue() {
|
void Options::Option::clearValue() {
|
||||||
_field->setText(QString());
|
field()->setText(QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Options::Option::setPlaceholder() const {
|
void Options::Option::setPlaceholder() const {
|
||||||
_field->setPlaceholder(langFactory(lng_polls_create_option_add));
|
field()->setPlaceholder(langFactory(lng_polls_create_option_add));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Options::Option::toggleRemoveAlways(bool toggled) {
|
void Options::Option::toggleRemoveAlways(bool toggled) {
|
||||||
@ -293,16 +317,16 @@ void Options::Option::toggleRemoveAlways(bool toggled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
not_null<Ui::InputField*> Options::Option::field() const {
|
not_null<Ui::InputField*> Options::Option::field() const {
|
||||||
return _field.get();
|
return _field->entity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Options::Option::removePlaceholder() const {
|
void Options::Option::removePlaceholder() const {
|
||||||
_field->setPlaceholder(nullptr);
|
field()->setPlaceholder(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
PollAnswer Options::Option::toPollAnswer(char id) const {
|
PollAnswer Options::Option::toPollAnswer(char id) const {
|
||||||
return PollAnswer{
|
return PollAnswer{
|
||||||
_field->getLastText().trimmed(),
|
field()->getLastText().trimmed(),
|
||||||
QByteArray(1, id)
|
QByteArray(1, id)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -344,6 +368,23 @@ rpl::producer<> Options::backspaceInFront() const {
|
|||||||
return _backspaceInFront.events();
|
return _backspaceInFront.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Options::Option::show(anim::type animated) {
|
||||||
|
_field->hide(anim::type::instant);
|
||||||
|
_field->show(animated);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Options::Option::destroy(FnMut<void()> done) {
|
||||||
|
if (anim::Disabled() || _field->isHidden()) {
|
||||||
|
Ui::PostponeCall(std::move(done));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_field->hide(anim::type::normal);
|
||||||
|
App::CallDelayed(
|
||||||
|
st::slideWrapDuration * 2,
|
||||||
|
_field.get(),
|
||||||
|
std::move(done));
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<PollAnswer> Options::toPollAnswers() const {
|
std::vector<PollAnswer> Options::toPollAnswers() const {
|
||||||
auto result = std::vector<PollAnswer>();
|
auto result = std::vector<PollAnswer>();
|
||||||
result.reserve(_list.size());
|
result.reserve(_list.size());
|
||||||
@ -405,10 +446,19 @@ void Options::removeEmptyTail() {
|
|||||||
if (focusLast) {
|
if (focusLast) {
|
||||||
emptyItem->setFocus();
|
emptyItem->setFocus();
|
||||||
}
|
}
|
||||||
|
for (auto i = emptyItem + 1; i != end; ++i) {
|
||||||
|
destroy(std::move(*i));
|
||||||
|
}
|
||||||
_list.erase(emptyItem + 1, end);
|
_list.erase(emptyItem + 1, end);
|
||||||
fixAfterErase();
|
fixAfterErase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Options::destroy(Option &&option) {
|
||||||
|
const auto field = option.field();
|
||||||
|
option.destroy([=] { removeDestroyed(field); });
|
||||||
|
_destroyed.emplace(std::move(option));
|
||||||
|
}
|
||||||
|
|
||||||
void Options::fixAfterErase() {
|
void Options::fixAfterErase() {
|
||||||
Expects(!_list.empty());
|
Expects(!_list.empty());
|
||||||
|
|
||||||
@ -434,7 +484,7 @@ void Options::addEmptyOption() {
|
|||||||
_list.push_back(Option::Create(
|
_list.push_back(Option::Create(
|
||||||
_outer,
|
_outer,
|
||||||
_container,
|
_container,
|
||||||
_position + _list.size()));
|
_position + _list.size() + _destroyed.size()));
|
||||||
const auto field = _list.back().field();
|
const auto field = _list.back().field();
|
||||||
QObject::connect(field, &Ui::InputField::submitted, [=] {
|
QObject::connect(field, &Ui::InputField::submitted, [=] {
|
||||||
const auto index = findField(field);
|
const auto index = findField(field);
|
||||||
@ -482,15 +532,23 @@ void Options::addEmptyOption() {
|
|||||||
if (item->hasFocus()) {
|
if (item->hasFocus()) {
|
||||||
(item + 1)->setFocus();
|
(item + 1)->setFocus();
|
||||||
}
|
}
|
||||||
|
destroy(std::move(*item));
|
||||||
_list.erase(item);
|
_list.erase(item);
|
||||||
fixAfterErase();
|
fixAfterErase();
|
||||||
validateState();
|
validateState();
|
||||||
}));
|
}));
|
||||||
}, field->lifetime());
|
}, field->lifetime());
|
||||||
|
|
||||||
|
_list.back().show((_list.size() == 1)
|
||||||
|
? anim::type::instant
|
||||||
|
: anim::type::normal);
|
||||||
//fixShadows();
|
//fixShadows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Options::removeDestroyed(not_null<Ui::InputField*> field) {
|
||||||
|
_destroyed.erase(_destroyed.find(field));
|
||||||
|
}
|
||||||
|
|
||||||
void Options::validateState() {
|
void Options::validateState() {
|
||||||
checkLastOption();
|
checkLastOption();
|
||||||
_valid = (ranges::count_if(_list, &Option::isGood) > 1)
|
_valid = (ranges::count_if(_list, &Option::isGood) > 1)
|
||||||
|
@ -111,7 +111,6 @@ private:
|
|||||||
void resetAnswersAnimation() const;
|
void resetAnswersAnimation() const;
|
||||||
void step_radial(TimeMs ms, bool timer);
|
void step_radial(TimeMs ms, bool timer);
|
||||||
|
|
||||||
void checkPollResultsReload(TimeMs ms) const;
|
|
||||||
void toggleRipple(Answer &answer, bool pressed);
|
void toggleRipple(Answer &answer, bool pressed);
|
||||||
|
|
||||||
not_null<PollData*> _poll;
|
not_null<PollData*> _poll;
|
||||||
|
Loading…
Reference in New Issue
Block a user