668 lines
19 KiB
C++
668 lines
19 KiB
C++
/*
|
|
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 "settings/business/settings_working_hours.h"
|
|
|
|
#include "base/event_filter.h"
|
|
#include "base/unixtime.h"
|
|
#include "core/application.h"
|
|
#include "data/business/data_business_info.h"
|
|
#include "data/data_session.h"
|
|
#include "data/data_user.h"
|
|
#include "lang/lang_keys.h"
|
|
#include "main/main_session.h"
|
|
#include "settings/business/settings_recipients_helper.h"
|
|
#include "ui/layers/generic_box.h"
|
|
#include "ui/text/text_utilities.h"
|
|
#include "ui/widgets/buttons.h"
|
|
#include "ui/widgets/checkbox.h"
|
|
#include "ui/widgets/labels.h"
|
|
#include "ui/widgets/vertical_drum_picker.h"
|
|
#include "ui/wrap/vertical_layout.h"
|
|
#include "ui/wrap/slide_wrap.h"
|
|
#include "ui/vertical_list.h"
|
|
#include "window/window_session_controller.h"
|
|
#include "styles/style_boxes.h"
|
|
#include "styles/style_layers.h"
|
|
#include "styles/style_settings.h"
|
|
|
|
namespace Settings {
|
|
namespace {
|
|
|
|
constexpr auto kDay = Data::WorkingInterval::kDay;
|
|
constexpr auto kWeek = Data::WorkingInterval::kWeek;
|
|
constexpr auto kInNextDayMax = Data::WorkingInterval::kInNextDayMax;
|
|
|
|
class WorkingHours : public BusinessSection<WorkingHours> {
|
|
public:
|
|
WorkingHours(
|
|
QWidget *parent,
|
|
not_null<Window::SessionController*> controller);
|
|
~WorkingHours();
|
|
|
|
[[nodiscard]] rpl::producer<QString> title() override;
|
|
|
|
private:
|
|
void setupContent(not_null<Window::SessionController*> controller);
|
|
void save();
|
|
|
|
rpl::variable<Data::WorkingHours> _hours;
|
|
rpl::variable<bool> _enabled;
|
|
|
|
};
|
|
|
|
[[nodiscard]] QString TimezoneFullName(const Data::Timezone &data) {
|
|
const auto abs = std::abs(data.utcOffset);
|
|
const auto hours = abs / 3600;
|
|
const auto minutes = (abs % 3600) / 60;
|
|
const auto seconds = abs % 60;
|
|
const auto sign = (data.utcOffset < 0) ? '-' : '+';
|
|
const auto prefix = u"(UTC"_q
|
|
+ sign
|
|
+ QString::number(hours)
|
|
+ u":"_q
|
|
+ QString::number(minutes).rightJustified(2, u'0')
|
|
+ u")"_q;
|
|
return prefix + ' ' + data.name;
|
|
}
|
|
|
|
[[nodiscard]] QString FormatDayTime(
|
|
TimeId time,
|
|
bool showEndAsNextDay = false) {
|
|
const auto wrap = [](TimeId value) {
|
|
const auto hours = value / 3600;
|
|
const auto minutes = (value % 3600) / 60;
|
|
return QString::number(hours).rightJustified(2, u'0')
|
|
+ ':'
|
|
+ QString::number(minutes).rightJustified(2, u'0');
|
|
};
|
|
return (time > kDay || (showEndAsNextDay && time == kDay))
|
|
? tr::lng_hours_next_day(tr::now, lt_time, wrap(time - kDay))
|
|
: wrap(time == kDay ? 0 : time);
|
|
}
|
|
|
|
[[nodiscard]] QString JoinIntervals(const Data::WorkingIntervals &data) {
|
|
auto result = QStringList();
|
|
result.reserve(data.list.size());
|
|
for (const auto &interval : data.list) {
|
|
const auto start = FormatDayTime(interval.start);
|
|
const auto end = FormatDayTime(interval.end);
|
|
result.push_back(start + u" - "_q + end);
|
|
}
|
|
return result.join(u", "_q);
|
|
}
|
|
|
|
void EditTimeBox(
|
|
not_null<Ui::GenericBox*> box,
|
|
TimeId low,
|
|
TimeId high,
|
|
TimeId value,
|
|
Fn<void(TimeId)> save) {
|
|
Expects(low <= high);
|
|
|
|
const auto values = (high - low + 60) / 60;
|
|
const auto startIndex = (value - low) / 60;
|
|
|
|
const auto content = box->addRow(object_ptr<Ui::FixedHeightWidget>(
|
|
box,
|
|
st::settingsWorkingHoursPicker));
|
|
|
|
const auto font = st::boxTextFont;
|
|
const auto itemHeight = st::settingsWorkingHoursPickerItemHeight;
|
|
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);
|
|
p.drawText(r, FormatDayTime(low + index * 60, true), style::al_center);
|
|
p.restore();
|
|
};
|
|
|
|
const auto picker = Ui::CreateChild<Ui::VerticalDrumPicker>(
|
|
content,
|
|
std::move(paintCallback),
|
|
values,
|
|
itemHeight,
|
|
startIndex);
|
|
|
|
content->sizeValue(
|
|
) | rpl::start_with_next([=](const QSize &s) {
|
|
picker->resize(s.width(), s.height());
|
|
picker->moveToLeft((s.width() - picker->width()) / 2, 0);
|
|
}, content->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(content, [=](not_null<QEvent*> e) {
|
|
if ((e->type() == QEvent::MouseButtonPress)
|
|
|| (e->type() == QEvent::MouseButtonRelease)
|
|
|| (e->type() == QEvent::MouseMove)) {
|
|
picker->handleMouseEvent(static_cast<QMouseEvent*>(e.get()));
|
|
} else if (e->type() == QEvent::Wheel) {
|
|
picker->handleWheelEvent(static_cast<QWheelEvent*>(e.get()));
|
|
}
|
|
return base::EventFilterResult::Continue;
|
|
});
|
|
base::install_event_filter(box, [=](not_null<QEvent*> e) {
|
|
if (e->type() == QEvent::KeyPress) {
|
|
picker->handleKeyEvent(static_cast<QKeyEvent*>(e.get()));
|
|
}
|
|
return base::EventFilterResult::Continue;
|
|
});
|
|
|
|
box->addButton(tr::lng_settings_save(), [=] {
|
|
const auto weak = Ui::MakeWeak(box);
|
|
save(std::clamp(low + picker->index() * 60, low, high));
|
|
if (const auto strong = weak.data()) {
|
|
strong->closeBox();
|
|
}
|
|
});
|
|
box->addButton(tr::lng_cancel(), [=] {
|
|
box->closeBox();
|
|
});
|
|
}
|
|
|
|
void EditDayBox(
|
|
not_null<Ui::GenericBox*> box,
|
|
rpl::producer<QString> title,
|
|
Data::WorkingIntervals intervals,
|
|
Fn<void(Data::WorkingIntervals)> save) {
|
|
box->setTitle(std::move(title));
|
|
box->setWidth(st::boxWideWidth);
|
|
struct State {
|
|
rpl::variable<Data::WorkingIntervals> data;
|
|
};
|
|
const auto state = box->lifetime().make_state<State>(State{
|
|
.data = std::move(intervals),
|
|
});
|
|
|
|
const auto container = box->verticalLayout();
|
|
const auto rows = container->add(
|
|
object_ptr<Ui::VerticalLayout>(container));
|
|
const auto makeRow = [=](
|
|
Data::WorkingInterval interval,
|
|
TimeId min,
|
|
TimeId max) {
|
|
auto result = object_ptr<Ui::VerticalLayout>(rows);
|
|
const auto raw = result.data();
|
|
AddDivider(raw);
|
|
AddSkip(raw);
|
|
AddButtonWithLabel(
|
|
raw,
|
|
tr::lng_hours_opening(),
|
|
rpl::single(FormatDayTime(interval.start, true)),
|
|
st::settingsButtonNoIcon
|
|
)->setClickedCallback([=] {
|
|
const auto max = std::max(min, interval.end - 60);
|
|
const auto now = std::clamp(interval.start, min, max);
|
|
const auto save = crl::guard(box, [=](TimeId value) {
|
|
auto now = state->data.current();
|
|
const auto i = ranges::find(now.list, interval);
|
|
if (i != end(now.list)) {
|
|
i->start = value;
|
|
state->data = now.normalized();
|
|
}
|
|
});
|
|
box->getDelegate()->show(Box(EditTimeBox, min, max, now, save));
|
|
});
|
|
AddButtonWithLabel(
|
|
raw,
|
|
tr::lng_hours_closing(),
|
|
rpl::single(FormatDayTime(interval.end, true)),
|
|
st::settingsButtonNoIcon
|
|
)->setClickedCallback([=] {
|
|
const auto min = std::min(max, interval.start + 60);
|
|
const auto now = std::clamp(interval.end, min, max);
|
|
const auto save = crl::guard(box, [=](TimeId value) {
|
|
auto now = state->data.current();
|
|
const auto i = ranges::find(now.list, interval);
|
|
if (i != end(now.list)) {
|
|
i->end = value;
|
|
state->data = now.normalized();
|
|
}
|
|
});
|
|
box->getDelegate()->show(Box(EditTimeBox, min, max, now, save));
|
|
});
|
|
raw->add(object_ptr<Ui::SettingsButton>(
|
|
raw,
|
|
tr::lng_hours_remove(),
|
|
st::settingsAttentionButton
|
|
))->setClickedCallback([=] {
|
|
auto now = state->data.current();
|
|
const auto i = ranges::find(now.list, interval);
|
|
if (i != end(now.list)) {
|
|
now.list.erase(i);
|
|
state->data = std::move(now);
|
|
}
|
|
});
|
|
AddSkip(raw);
|
|
|
|
return result;
|
|
};
|
|
|
|
const auto addWrap = container->add(
|
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
|
container,
|
|
object_ptr<Ui::VerticalLayout>(container)));
|
|
AddDivider(addWrap->entity());
|
|
AddSkip(addWrap->entity());
|
|
const auto add = addWrap->entity()->add(
|
|
object_ptr<Ui::SettingsButton>(
|
|
container,
|
|
tr::lng_hours_add_button(),
|
|
st::settingsButtonLightNoIcon));
|
|
add->setClickedCallback([=] {
|
|
auto now = state->data.current();
|
|
if (now.list.empty()) {
|
|
now.list.push_back({ 8 * 3600, 20 * 3600 });
|
|
} else if (const auto last = now.list.back().end; last + 60 < kDay) {
|
|
const auto from = std::max(
|
|
std::min(last + 30 * 60, kDay - 30 * 60),
|
|
last + 60);
|
|
const auto till = std::min(from + 4 * 3600, kDay + 30 * 60);
|
|
now.list.push_back({ from, from + 4 * 3600 });
|
|
}
|
|
state->data = std::move(now);
|
|
});
|
|
|
|
state->data.value(
|
|
) | rpl::start_with_next([=](const Data::WorkingIntervals &data) {
|
|
const auto count = int(data.list.size());
|
|
for (auto i = 0; i != count; ++i) {
|
|
const auto min = (i == 0) ? 0 : (data.list[i - 1].end + 60);
|
|
const auto max = (i == count - 1)
|
|
? (kDay + kInNextDayMax)
|
|
: (data.list[i + 1].start - 60);
|
|
rows->insert(i, makeRow(data.list[i], min, max));
|
|
if (rows->count() > i + 1) {
|
|
delete rows->widgetAt(i + 1);
|
|
}
|
|
}
|
|
while (rows->count() > count) {
|
|
delete rows->widgetAt(count);
|
|
}
|
|
rows->resizeToWidth(st::boxWideWidth);
|
|
addWrap->toggle(data.list.empty()
|
|
|| data.list.back().end + 60 < kDay, anim::type::instant);
|
|
add->clearState();
|
|
}, add->lifetime());
|
|
addWrap->finishAnimating();
|
|
|
|
AddSkip(container);
|
|
AddDividerText(container, tr::lng_hours_about_day());
|
|
|
|
box->addButton(tr::lng_settings_save(), [=] {
|
|
const auto weak = Ui::MakeWeak(box);
|
|
save(state->data.current());
|
|
if (const auto strong = weak.data()) {
|
|
strong->closeBox();
|
|
}
|
|
});
|
|
box->addButton(tr::lng_cancel(), [=] {
|
|
box->closeBox();
|
|
});
|
|
}
|
|
|
|
void ChooseTimezoneBox(
|
|
not_null<Ui::GenericBox*> box,
|
|
std::vector<Data::Timezone> list,
|
|
QString id,
|
|
Fn<void(QString)> save) {
|
|
Expects(!list.empty());
|
|
box->setWidth(st::boxWideWidth);
|
|
box->setTitle(tr::lng_hours_time_zone_title());
|
|
|
|
const auto height = st::boxWideWidth;
|
|
box->setMaxHeight(height);
|
|
|
|
ranges::sort(list, ranges::less(), [](const Data::Timezone &value) {
|
|
return std::pair(value.utcOffset, value.name);
|
|
});
|
|
|
|
if (!ranges::contains(list, id, &Data::Timezone::id)) {
|
|
id = Data::FindClosestTimezoneId(list);
|
|
}
|
|
const auto i = ranges::find(list, id, &Data::Timezone::id);
|
|
const auto value = int(i - begin(list));
|
|
const auto group = std::make_shared<Ui::RadiobuttonGroup>(value);
|
|
const auto radioPadding = st::defaultCheckbox.margin;
|
|
const auto max = std::max(radioPadding.top(), radioPadding.bottom());
|
|
auto index = 0;
|
|
auto padding = st::boxRowPadding + QMargins(0, max, 0, max);
|
|
auto selected = (Ui::Radiobutton*)nullptr;
|
|
for (const auto &entry : list) {
|
|
const auto button = box->addRow(
|
|
object_ptr<Ui::Radiobutton>(
|
|
box,
|
|
group,
|
|
index++,
|
|
TimezoneFullName(entry)),
|
|
padding);
|
|
if (index == value + 1) {
|
|
selected = button;
|
|
}
|
|
padding = st::boxRowPadding + QMargins(0, 0, 0, max);
|
|
}
|
|
if (selected) {
|
|
box->verticalLayout()->resizeToWidth(st::boxWideWidth);
|
|
const auto y = selected->y() - (height - selected->height()) / 2;
|
|
box->setInitScrollCallback([=] {
|
|
box->scrollToY(y);
|
|
});
|
|
}
|
|
group->setChangedCallback([=](int index) {
|
|
const auto weak = Ui::MakeWeak(box);
|
|
save(list[index].id);
|
|
if (const auto strong = weak.data()) {
|
|
strong->closeBox();
|
|
}
|
|
});
|
|
box->addButton(tr::lng_close(), [=] {
|
|
box->closeBox();
|
|
});
|
|
}
|
|
|
|
void AddWeekButton(
|
|
not_null<Ui::VerticalLayout*> container,
|
|
not_null<Window::SessionController*> controller,
|
|
int index,
|
|
not_null<rpl::variable<Data::WorkingHours>*> data) {
|
|
auto label = [&] {
|
|
switch (index) {
|
|
case 0: return tr::lng_hours_monday();
|
|
case 1: return tr::lng_hours_tuesday();
|
|
case 2: return tr::lng_hours_wednesday();
|
|
case 3: return tr::lng_hours_thursday();
|
|
case 4: return tr::lng_hours_friday();
|
|
case 5: return tr::lng_hours_saturday();
|
|
case 6: return tr::lng_hours_sunday();
|
|
}
|
|
Unexpected("Index in AddWeekButton.");
|
|
}();
|
|
const auto &st = st::settingsWorkingHoursWeek;
|
|
const auto button = AddButtonWithIcon(
|
|
container,
|
|
rpl::duplicate(label),
|
|
st);
|
|
button->setClickedCallback([=] {
|
|
const auto done = [=](Data::WorkingIntervals intervals) {
|
|
auto now = data->current();
|
|
now.intervals = ReplaceDayIntervals(
|
|
now.intervals,
|
|
index,
|
|
std::move(intervals));
|
|
*data = now.normalized();
|
|
};
|
|
controller->show(Box(
|
|
EditDayBox,
|
|
rpl::duplicate(label),
|
|
ExtractDayIntervals(data->current().intervals, index),
|
|
crl::guard(button, done)));
|
|
});
|
|
|
|
const auto toggleButton = Ui::CreateChild<Ui::SettingsButton>(
|
|
container.get(),
|
|
nullptr,
|
|
st);
|
|
const auto checkView = button->lifetime().make_state<Ui::ToggleView>(
|
|
st.toggle,
|
|
false,
|
|
[=] { toggleButton->update(); });
|
|
|
|
auto status = data->value(
|
|
) | rpl::map([=](const Data::WorkingHours &data) -> rpl::producer<QString> {
|
|
using namespace Data;
|
|
|
|
const auto intervals = ExtractDayIntervals(data.intervals, index);
|
|
const auto empty = intervals.list.empty();
|
|
if (checkView->checked() == empty) {
|
|
checkView->setChecked(!empty, anim::type::instant);
|
|
}
|
|
if (!intervals) {
|
|
return tr::lng_hours_closed();
|
|
} else if (IsFullOpen(intervals)) {
|
|
return tr::lng_hours_open_full();
|
|
}
|
|
return rpl::single(JoinIntervals(intervals));
|
|
}) | rpl::flatten_latest();
|
|
const auto details = Ui::CreateChild<Ui::FlatLabel>(
|
|
button.get(),
|
|
std::move(status),
|
|
st::settingsWorkingHoursDetails);
|
|
details->show();
|
|
details->moveToLeft(
|
|
st.padding.left(),
|
|
st.padding.top() + st.height - details->height());
|
|
details->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
|
|
const auto separator = Ui::CreateChild<Ui::RpWidget>(container.get());
|
|
separator->paintRequest(
|
|
) | rpl::start_with_next([=, bg = st.textBgOver] {
|
|
auto p = QPainter(separator);
|
|
p.fillRect(separator->rect(), bg);
|
|
}, separator->lifetime());
|
|
const auto separatorHeight = st.height - 2 * st.toggle.border;
|
|
button->geometryValue(
|
|
) | rpl::start_with_next([=](const QRect &r) {
|
|
const auto w = st::rightsButtonToggleWidth;
|
|
toggleButton->setGeometry(
|
|
r.x() + r.width() - w,
|
|
r.y(),
|
|
w,
|
|
r.height());
|
|
separator->setGeometry(
|
|
toggleButton->x() - st::lineWidth,
|
|
r.y() + (r.height() - separatorHeight) / 2,
|
|
st::lineWidth,
|
|
separatorHeight);
|
|
}, toggleButton->lifetime());
|
|
|
|
const auto checkWidget = Ui::CreateChild<Ui::RpWidget>(toggleButton);
|
|
checkWidget->resize(checkView->getSize());
|
|
checkWidget->paintRequest(
|
|
) | rpl::start_with_next([=] {
|
|
auto p = QPainter(checkWidget);
|
|
checkView->paint(p, 0, 0, checkWidget->width());
|
|
}, checkWidget->lifetime());
|
|
toggleButton->sizeValue(
|
|
) | rpl::start_with_next([=](const QSize &s) {
|
|
checkWidget->moveToRight(
|
|
st.toggleSkip,
|
|
(s.height() - checkWidget->height()) / 2);
|
|
}, toggleButton->lifetime());
|
|
|
|
toggleButton->setClickedCallback([=] {
|
|
const auto enabled = !checkView->checked();
|
|
checkView->setChecked(enabled, anim::type::normal);
|
|
auto now = data->current();
|
|
now.intervals = ReplaceDayIntervals(
|
|
now.intervals,
|
|
index,
|
|
(enabled
|
|
? Data::WorkingIntervals{ { { 0, kDay } } }
|
|
: Data::WorkingIntervals()));
|
|
*data = now.normalized();
|
|
});
|
|
}
|
|
|
|
WorkingHours::WorkingHours(
|
|
QWidget *parent,
|
|
not_null<Window::SessionController*> controller)
|
|
: BusinessSection(parent, controller) {
|
|
setupContent(controller);
|
|
}
|
|
|
|
WorkingHours::~WorkingHours() {
|
|
if (!Core::Quitting()) {
|
|
save();
|
|
}
|
|
}
|
|
|
|
rpl::producer<QString> WorkingHours::title() {
|
|
return tr::lng_hours_title();
|
|
}
|
|
|
|
void WorkingHours::setupContent(
|
|
not_null<Window::SessionController*> controller) {
|
|
using namespace rpl::mappers;
|
|
|
|
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
|
|
|
struct State {
|
|
rpl::variable<Data::Timezones> timezones;
|
|
bool timezoneEditPending = false;
|
|
};
|
|
const auto info = &controller->session().data().businessInfo();
|
|
const auto state = content->lifetime().make_state<State>(State{
|
|
.timezones = info->timezonesValue(),
|
|
});
|
|
_hours = controller->session().user()->businessDetails().hours;
|
|
|
|
AddDividerTextWithLottie(content, {
|
|
.lottie = u"hours"_q,
|
|
.lottieSize = st::settingsCloudPasswordIconSize,
|
|
.lottieMargins = st::peerAppearanceIconPadding,
|
|
.showFinished = showFinishes(),
|
|
.about = tr::lng_hours_about(Ui::Text::WithEntities),
|
|
.aboutMargins = st::peerAppearanceCoverLabelMargin,
|
|
});
|
|
|
|
Ui::AddSkip(content);
|
|
const auto enabled = content->add(object_ptr<Ui::SettingsButton>(
|
|
content,
|
|
tr::lng_hours_show(),
|
|
st::settingsButtonNoIcon
|
|
))->toggleOn(rpl::single(bool(_hours.current())));
|
|
|
|
_enabled = enabled->toggledValue();
|
|
|
|
const auto wrap = content->add(
|
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
|
content,
|
|
object_ptr<Ui::VerticalLayout>(content)));
|
|
const auto inner = wrap->entity();
|
|
|
|
Ui::AddSkip(inner);
|
|
Ui::AddDivider(inner);
|
|
Ui::AddSkip(inner);
|
|
|
|
for (auto i = 0; i != 7; ++i) {
|
|
AddWeekButton(inner, controller, i, &_hours);
|
|
}
|
|
|
|
Ui::AddSkip(inner);
|
|
Ui::AddDivider(inner);
|
|
Ui::AddSkip(inner);
|
|
|
|
state->timezones.value(
|
|
) | rpl::filter([=](const Data::Timezones &value) {
|
|
return !value.list.empty();
|
|
}) | rpl::start_with_next([=](const Data::Timezones &value) {
|
|
const auto now = _hours.current().timezoneId;
|
|
if (!ranges::contains(value.list, now, &Data::Timezone::id)) {
|
|
auto copy = _hours.current();
|
|
copy.timezoneId = Data::FindClosestTimezoneId(value.list);
|
|
_hours = std::move(copy);
|
|
}
|
|
}, inner->lifetime());
|
|
|
|
auto timezoneLabel = rpl::combine(
|
|
_hours.value(),
|
|
state->timezones.value()
|
|
) | rpl::map([](
|
|
const Data::WorkingHours &hours,
|
|
const Data::Timezones &timezones) {
|
|
const auto i = ranges::find(
|
|
timezones.list,
|
|
hours.timezoneId,
|
|
&Data::Timezone::id);
|
|
return (i != end(timezones.list)) ? TimezoneFullName(*i) : QString();
|
|
});
|
|
const auto editTimezone = [=](const std::vector<Data::Timezone> &list) {
|
|
const auto was = _hours.current().timezoneId;
|
|
controller->show(Box(ChooseTimezoneBox, list, was, [=](QString id) {
|
|
if (id != was) {
|
|
auto copy = _hours.current();
|
|
copy.timezoneId = id;
|
|
_hours = std::move(copy);
|
|
}
|
|
}));
|
|
};
|
|
AddButtonWithLabel(
|
|
inner,
|
|
tr::lng_hours_time_zone(),
|
|
std::move(timezoneLabel),
|
|
st::settingsButtonNoIcon
|
|
)->setClickedCallback([=] {
|
|
const auto &list = state->timezones.current().list;
|
|
if (!list.empty()) {
|
|
editTimezone(list);
|
|
} else {
|
|
state->timezoneEditPending = true;
|
|
}
|
|
});
|
|
|
|
if (state->timezones.current().list.empty()) {
|
|
state->timezones.value(
|
|
) | rpl::filter([](const Data::Timezones &value) {
|
|
return !value.list.empty();
|
|
}) | rpl::start_with_next([=](const Data::Timezones &value) {
|
|
if (state->timezoneEditPending) {
|
|
state->timezoneEditPending = false;
|
|
editTimezone(value.list);
|
|
}
|
|
}, inner->lifetime());
|
|
}
|
|
|
|
wrap->toggleOn(enabled->toggledValue());
|
|
wrap->finishAnimating();
|
|
|
|
Ui::ResizeFitChild(this, content);
|
|
}
|
|
|
|
void WorkingHours::save() {
|
|
const auto show = controller()->uiShow();
|
|
controller()->session().data().businessInfo().saveWorkingHours(
|
|
_enabled.current() ? _hours.current() : Data::WorkingHours(),
|
|
[=](QString error) { show->showToast(error); });
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Type WorkingHoursId() {
|
|
return WorkingHours::Id();
|
|
}
|
|
|
|
} // namespace Settings
|