Add slide animations in CreatePollBox.

This commit is contained in:
John Preston 2018-12-25 11:41:22 +04:00
parent 6f176803d4
commit f291e365e5
2 changed files with 80 additions and 23 deletions

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_poll.h"
#include "ui/toast/toast.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/shadow.h"
#include "ui/widgets/labels.h"
@ -56,6 +57,9 @@ private:
void toggleRemoveAlways(bool toggled);
void show(anim::type animated);
void destroy(FnMut<void()> done);
//[[nodisacrd]] bool hasShadow() const;
//void destroyShadow();
@ -75,6 +79,21 @@ private:
[[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:
Option() = default;
@ -82,7 +101,7 @@ private:
void createRemove();
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::CrossButton> _remove;
rpl::variable<bool> *_removeAlways = nullptr;
@ -97,12 +116,15 @@ private:
void checkLastOption();
void validateState();
void fixAfterErase();
void destroy(Option &&option);
void removeDestroyed(not_null<Ui::InputField*> field);
int findField(not_null<Ui::InputField*> field) const;
not_null<QWidget*> _outer;
not_null<Ui::VerticalLayout*> _container;
int _position = 0;
std::vector<Option> _list;
std::set<Option, std::less<>> _destroyed;
rpl::variable<bool> _valid = false;
rpl::variable<int> _usedCount = 0;
rpl::event_stream<not_null<QWidget*>> _scrollToWidget;
@ -157,12 +179,14 @@ Options::Option Options::Option::Create(
auto result = Option();
const auto field = container->insert(
position,
object_ptr<Ui::InputField>(
object_ptr<Ui::SlideWrap<Ui::InputField>>(
container,
st::createPollOptionField,
langFactory(lng_polls_create_option_add)));
InitField(outer, field);
field->setMaxLength(kOptionLimit + kErrorLimit);
object_ptr<Ui::InputField>(
container,
st::createPollOptionField,
langFactory(lng_polls_create_option_add))));
InitField(outer, field->entity());
field->entity()->setMaxLength(kOptionLimit + kErrorLimit);
result._field.reset(field);
result.createShadow();
@ -181,9 +205,9 @@ void Options::Option::createShadow() {
if (_shadow) {
return;
}
const auto value = Ui::CreateChild<Ui::PlainShadow>(_field.get());
const auto value = Ui::CreateChild<Ui::PlainShadow>(field().get());
value->show();
_field->sizeValue(
field()->sizeValue(
) | rpl::start_with_next([=](QSize size) {
const auto left = st::createPollFieldPadding.left();
value->setGeometry(
@ -202,11 +226,11 @@ void Options::Option::createShadow() {
void Options::Option::createRemove() {
using namespace rpl::mappers;
const auto field = _field.get();
const auto field = this->field();
auto &lifetime = field->lifetime();
const auto remove = Ui::CreateChild<Ui::CrossButton>(
field,
field.get(),
st::createPollOptionRemove);
remove->hide(anim::type::instant);
@ -239,7 +263,7 @@ void Options::Option::createRemove() {
void Options::Option::createWarning() {
using namespace rpl::mappers;
const auto field = _field.get();
const auto field = this->field();
const auto warning = CreateWarningLabel(
field,
field,
@ -261,31 +285,31 @@ void Options::Option::createWarning() {
}
bool Options::Option::isEmpty() const {
return _field->getLastText().trimmed().isEmpty();
return field()->getLastText().trimmed().isEmpty();
}
bool Options::Option::isGood() const {
return !_field->getLastText().trimmed().isEmpty() && !isTooLong();
return !field()->getLastText().trimmed().isEmpty() && !isTooLong();
}
bool Options::Option::isTooLong() const {
return (_field->getLastText().size() > kOptionLimit);
return (field()->getLastText().size() > kOptionLimit);
}
bool Options::Option::hasFocus() const {
return _field->hasFocus();
return field()->hasFocus();
}
void Options::Option::setFocus() const {
FocusAtEnd(_field);
FocusAtEnd(field());
}
void Options::Option::clearValue() {
_field->setText(QString());
field()->setText(QString());
}
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) {
@ -293,16 +317,16 @@ void Options::Option::toggleRemoveAlways(bool toggled) {
}
not_null<Ui::InputField*> Options::Option::field() const {
return _field.get();
return _field->entity();
}
void Options::Option::removePlaceholder() const {
_field->setPlaceholder(nullptr);
field()->setPlaceholder(nullptr);
}
PollAnswer Options::Option::toPollAnswer(char id) const {
return PollAnswer{
_field->getLastText().trimmed(),
field()->getLastText().trimmed(),
QByteArray(1, id)
};
}
@ -344,6 +368,23 @@ rpl::producer<> Options::backspaceInFront() const {
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 {
auto result = std::vector<PollAnswer>();
result.reserve(_list.size());
@ -405,10 +446,19 @@ void Options::removeEmptyTail() {
if (focusLast) {
emptyItem->setFocus();
}
for (auto i = emptyItem + 1; i != end; ++i) {
destroy(std::move(*i));
}
_list.erase(emptyItem + 1, end);
fixAfterErase();
}
void Options::destroy(Option &&option) {
const auto field = option.field();
option.destroy([=] { removeDestroyed(field); });
_destroyed.emplace(std::move(option));
}
void Options::fixAfterErase() {
Expects(!_list.empty());
@ -434,7 +484,7 @@ void Options::addEmptyOption() {
_list.push_back(Option::Create(
_outer,
_container,
_position + _list.size()));
_position + _list.size() + _destroyed.size()));
const auto field = _list.back().field();
QObject::connect(field, &Ui::InputField::submitted, [=] {
const auto index = findField(field);
@ -482,15 +532,23 @@ void Options::addEmptyOption() {
if (item->hasFocus()) {
(item + 1)->setFocus();
}
destroy(std::move(*item));
_list.erase(item);
fixAfterErase();
validateState();
}));
}, field->lifetime());
_list.back().show((_list.size() == 1)
? anim::type::instant
: anim::type::normal);
//fixShadows();
}
void Options::removeDestroyed(not_null<Ui::InputField*> field) {
_destroyed.erase(_destroyed.find(field));
}
void Options::validateState() {
checkLastOption();
_valid = (ranges::count_if(_list, &Option::isGood) > 1)

View File

@ -111,7 +111,6 @@ private:
void resetAnswersAnimation() const;
void step_radial(TimeMs ms, bool timer);
void checkPollResultsReload(TimeMs ms) const;
void toggleRipple(Answer &answer, bool pressed);
not_null<PollData*> _poll;