| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "ui/boxes/edit_birthday_box.h"
- #include "base/event_filter.h"
- #include "data/data_birthday.h"
- #include "lang/lang_keys.h"
- #include "ui/layers/generic_box.h"
- #include "ui/widgets/vertical_drum_picker.h"
- #include "ui/ui_utility.h"
- #include "styles/style_layers.h"
- #include "styles/style_settings.h"
- #include <QtCore/QDate>
- namespace Ui {
- class GenericBox;
- void EditBirthdayBox(
- not_null<Ui::GenericBox*> box,
- Data::Birthday current,
- Fn<void(Data::Birthday)> save) {
- box->setWidth(st::boxWideWidth);
- const auto content = box->addRow(object_ptr<Ui::FixedHeightWidget>(
- box,
- st::settingsWorkingHoursPicker));
- const auto font = st::boxTextFont;
- const auto itemHeight = st::settingsWorkingHoursPickerItemHeight;
- const auto picker = [=](
- int count,
- int startIndex,
- Fn<void(QPainter &p, QRectF rect, int index)> paint) {
- auto paintCallback = [=](
- QPainter &p,
- int index,
- float64 y,
- float64 distanceFromCenter,
- int outerWidth) {
- const auto r = QRectF(0, y, outerWidth, itemHeight);
- const auto progress = std::abs(distanceFromCenter);
- const auto revProgress = 1. - progress;
- p.save();
- p.translate(r.center());
- constexpr auto kMinYScale = 0.2;
- const auto yScale = kMinYScale
- + (1. - kMinYScale) * anim::easeOutCubic(1., revProgress);
- p.scale(1., yScale);
- p.translate(-r.center());
- p.setOpacity(revProgress);
- p.setFont(font);
- p.setPen(st::defaultFlatLabel.textFg);
- paint(p, r, index);
- p.restore();
- };
- return Ui::CreateChild<Ui::VerticalDrumPicker>(
- content,
- std::move(paintCallback),
- count,
- itemHeight,
- startIndex);
- };
- const auto nowDate = QDate::currentDate();
- const auto nowYear = nowDate.year();
- const auto nowMonth = nowDate.month();
- const auto nowDay = nowDate.day();
- const auto now = Data::Birthday(nowDay, nowMonth, nowYear);
- const auto max = current.year() ? std::max(now, current) : now;
- const auto maxYear = max.year();
- const auto minYear = Data::Birthday::kYearMin;
- const auto yearsCount = (maxYear - minYear + 2); // Last - not set.
- const auto yearsStartIndex = current.year()
- ? (current.year() - minYear)
- : (yearsCount - 1);
- const auto yearsPaint = [=](QPainter &p, QRectF rect, int index) {
- p.drawText(
- rect,
- (index < yearsCount - 1
- ? QString::number(minYear + index)
- : QString::fromUtf8("\xe2\x80\x94")),
- style::al_center);
- };
- const auto years = picker(yearsCount, yearsStartIndex, yearsPaint);
- struct State {
- rpl::variable<Ui::VerticalDrumPicker*> months;
- rpl::variable<Ui::VerticalDrumPicker*> days;
- };
- const auto state = content->lifetime().make_state<State>();
- // years->value() is valid only after size is set.
- rpl::combine(
- content->sizeValue(),
- state->months.value(),
- state->days.value()
- ) | rpl::start_with_next([=](
- QSize s,
- Ui::VerticalDrumPicker *months,
- Ui::VerticalDrumPicker *days) {
- const auto half = s.width() / 2;
- years->setGeometry(half * 3 / 2, 0, half / 2, s.height());
- if (months) {
- months->setGeometry(half / 2, 0, half, s.height());
- }
- if (days) {
- days->setGeometry(0, 0, half / 2, s.height());
- }
- }, content->lifetime());
- Ui::SendPendingMoveResizeEvents(years);
- years->value() | rpl::start_with_next([=](int yearsIndex) {
- const auto year = (yearsIndex == yearsCount - 1)
- ? 0
- : minYear + yearsIndex;
- const auto monthsCount = (year == maxYear)
- ? max.month()
- : 12;
- const auto monthsStartIndex = std::clamp(
- (state->months.current()
- ? state->months.current()->index()
- : current.month()
- ? (current.month() - 1)
- : (now.month() - 1)),
- 0,
- monthsCount - 1);
- const auto monthsPaint = [=](QPainter &p, QRectF rect, int index) {
- p.drawText(
- rect,
- Lang::Month(index + 1)(tr::now),
- style::al_center);
- };
- const auto updated = picker(
- monthsCount,
- monthsStartIndex,
- monthsPaint);
- delete state->months.current();
- state->months = updated;
- state->months.current()->show();
- }, years->lifetime());
- Ui::SendPendingMoveResizeEvents(state->months.current());
- state->months.value() | rpl::map([=](Ui::VerticalDrumPicker *picker) {
- return picker ? picker->value() : rpl::single(current.month()
- ? (current.month() - 1)
- : (now.month() - 1));
- }) | rpl::flatten_latest() | rpl::start_with_next([=](int monthIndex) {
- const auto month = monthIndex + 1;
- const auto yearsIndex = years->index();
- const auto year = (yearsIndex == yearsCount - 1)
- ? 0
- : minYear + yearsIndex;
- const auto daysCount = (year == maxYear && month == max.month())
- ? max.day()
- : (month == 2)
- ? ((!year || ((year % 4) && (!(year % 100) || (year % 400))))
- ? 29
- : 28)
- : ((month == 4) || (month == 6) || (month == 9) || (month == 11))
- ? 30
- : 31;
- const auto daysStartIndex = std::clamp(
- (state->days.current()
- ? state->days.current()->index()
- : current.day()
- ? (current.day() - 1)
- : (now.day() - 1)),
- 0,
- daysCount - 1);
- const auto daysPaint = [=](QPainter &p, QRectF rect, int index) {
- p.drawText(rect, QString::number(index + 1), style::al_center);
- };
- const auto updated = picker(
- daysCount,
- daysStartIndex,
- daysPaint);
- delete state->days.current();
- state->days = updated;
- state->days.current()->show();
- }, years->lifetime());
- content->paintRequest(
- ) | rpl::start_with_next([=](const QRect &r) {
- auto p = QPainter(content);
- p.fillRect(r, Qt::transparent);
- const auto lineRect = QRect(
- 0,
- content->height() / 2,
- content->width(),
- st::defaultInputField.borderActive);
- p.fillRect(lineRect.translated(0, itemHeight / 2), st::activeLineFg);
- p.fillRect(lineRect.translated(0, -itemHeight / 2), st::activeLineFg);
- }, content->lifetime());
- base::install_event_filter(box, [=](not_null<QEvent*> e) {
- if (e->type() == QEvent::KeyPress) {
- years->handleKeyEvent(static_cast<QKeyEvent*>(e.get()));
- }
- return base::EventFilterResult::Continue;
- });
- box->addButton(tr::lng_settings_save(), [=] {
- const auto result = Data::Birthday(
- state->days.current()->index() + 1,
- state->months.current()->index() + 1,
- ((years->index() == yearsCount - 1)
- ? 0
- : minYear + years->index()));
- box->closeBox();
- save(result);
- });
- box->addButton(tr::lng_cancel(), [=] {
- box->closeBox();
- });
- if (current) {
- box->addLeftButton(tr::lng_settings_birthday_reset(), [=] {
- box->closeBox();
- save(Data::Birthday());
- });
- }
- }
- } // namespace Ui
|