Support edit / save of greeting message settings.
This commit is contained in:
		
							parent
							
								
									e6b9ac2267
								
							
						
					
					
						commit
						dd7ccada2f
					
				
					 5 changed files with 266 additions and 11 deletions
				
			
		|  | @ -202,4 +202,18 @@ struct AwaySettings { | ||||||
| 		const AwaySettings &b) = default; | 		const AwaySettings &b) = default; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct GreetingSettings { | ||||||
|  | 	BusinessRecipients recipients; | ||||||
|  | 	int noActivityDays = 0; | ||||||
|  | 	int shortcutId = 0; | ||||||
|  | 
 | ||||||
|  | 	explicit operator bool() const { | ||||||
|  | 		return noActivityDays > 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	friend inline bool operator==( | ||||||
|  | 		const GreetingSettings &a, | ||||||
|  | 		const GreetingSettings &b) = default; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| } // namespace Data
 | } // namespace Data
 | ||||||
|  |  | ||||||
|  | @ -74,6 +74,20 @@ template <typename Flag> | ||||||
| 			| ranges::views::transform(&UserData::inputUser))); | 			| ranges::views::transform(&UserData::inputUser))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | [[nodiscard]] MTPInputBusinessGreetingMessage ToMTP( | ||||||
|  | 		const GreetingSettings &data) { | ||||||
|  | 	using Flag = MTPDinputBusinessGreetingMessage::Flag; | ||||||
|  | 	return MTP_inputBusinessGreetingMessage( | ||||||
|  | 		MTP_flags(RecipientsFlags(data.recipients, Flag())), | ||||||
|  | 		MTP_int(data.shortcutId), | ||||||
|  | 		MTP_vector_from_range( | ||||||
|  | 			(data.recipients.allButExcluded | ||||||
|  | 				? data.recipients.excluded | ||||||
|  | 				: data.recipients.included).list | ||||||
|  | 			| ranges::views::transform(&UserData::inputUser)), | ||||||
|  | 		MTP_int(data.noActivityDays)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
| 
 | 
 | ||||||
| BusinessInfo::BusinessInfo(not_null<Session*> owner) | BusinessInfo::BusinessInfo(not_null<Session*> owner) | ||||||
|  | @ -132,6 +146,40 @@ rpl::producer<> BusinessInfo::awaySettingsChanged() const { | ||||||
| 	return _awaySettingsChanged.events(); | 	return _awaySettingsChanged.events(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void BusinessInfo::applyGreetingSettings(GreetingSettings data) { | ||||||
|  | 	if (_greetingSettings == data) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	_greetingSettings = data; | ||||||
|  | 	_greetingSettingsChanged.fire({}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void BusinessInfo::saveGreetingSettings(GreetingSettings data) { | ||||||
|  | 	if (_greetingSettings == data) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	using Flag = MTPaccount_UpdateBusinessGreetingMessage::Flag; | ||||||
|  | 	_owner->session().api().request(MTPaccount_UpdateBusinessGreetingMessage( | ||||||
|  | 		MTP_flags(data ? Flag::f_message : Flag()), | ||||||
|  | 		data ? ToMTP(data) : MTPInputBusinessGreetingMessage() | ||||||
|  | 	)).send(); | ||||||
|  | 
 | ||||||
|  | 	_greetingSettings = std::move(data); | ||||||
|  | 	_greetingSettingsChanged.fire({}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool BusinessInfo::greetingSettingsLoaded() const { | ||||||
|  | 	return _greetingSettings.has_value(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | GreetingSettings BusinessInfo::greetingSettings() const { | ||||||
|  | 	return _greetingSettings.value_or(GreetingSettings()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | rpl::producer<> BusinessInfo::greetingSettingsChanged() const { | ||||||
|  | 	return _greetingSettingsChanged.events(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void BusinessInfo::preload() { | void BusinessInfo::preload() { | ||||||
| 	preloadTimezones(); | 	preloadTimezones(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -28,6 +28,12 @@ public: | ||||||
| 	[[nodiscard]] bool awaySettingsLoaded() const; | 	[[nodiscard]] bool awaySettingsLoaded() const; | ||||||
| 	[[nodiscard]] rpl::producer<> awaySettingsChanged() const; | 	[[nodiscard]] rpl::producer<> awaySettingsChanged() const; | ||||||
| 
 | 
 | ||||||
|  | 	void saveGreetingSettings(GreetingSettings data); | ||||||
|  | 	void applyGreetingSettings(GreetingSettings data); | ||||||
|  | 	[[nodiscard]] GreetingSettings greetingSettings() const; | ||||||
|  | 	[[nodiscard]] bool greetingSettingsLoaded() const; | ||||||
|  | 	[[nodiscard]] rpl::producer<> greetingSettingsChanged() const; | ||||||
|  | 
 | ||||||
| 	void preloadTimezones(); | 	void preloadTimezones(); | ||||||
| 	[[nodiscard]] rpl::producer<Timezones> timezonesValue() const; | 	[[nodiscard]] rpl::producer<Timezones> timezonesValue() const; | ||||||
| 
 | 
 | ||||||
|  | @ -35,9 +41,13 @@ private: | ||||||
| 	const not_null<Session*> _owner; | 	const not_null<Session*> _owner; | ||||||
| 
 | 
 | ||||||
| 	rpl::variable<Timezones> _timezones; | 	rpl::variable<Timezones> _timezones; | ||||||
|  | 
 | ||||||
| 	std::optional<AwaySettings> _awaySettings; | 	std::optional<AwaySettings> _awaySettings; | ||||||
| 	rpl::event_stream<> _awaySettingsChanged; | 	rpl::event_stream<> _awaySettingsChanged; | ||||||
| 
 | 
 | ||||||
|  | 	std::optional<GreetingSettings> _greetingSettings; | ||||||
|  | 	rpl::event_stream<> _greetingSettingsChanged; | ||||||
|  | 
 | ||||||
| 	mtpRequestId _timezonesRequestId = 0; | 	mtpRequestId _timezonesRequestId = 0; | ||||||
| 	int32 _timezonesHash = 0; | 	int32 _timezonesHash = 0; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -112,6 +112,20 @@ Data::BusinessRecipients RecipientsFromMTP( | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | [[nodiscard]] Data::GreetingSettings FromMTP( | ||||||
|  | 		not_null<Data::Session*> owner, | ||||||
|  | 		const tl::conditional<MTPBusinessGreetingMessage> &message) { | ||||||
|  | 	if (!message) { | ||||||
|  | 		return Data::GreetingSettings(); | ||||||
|  | 	} | ||||||
|  | 	const auto &data = message->data(); | ||||||
|  | 	return Data::GreetingSettings{ | ||||||
|  | 		.recipients = RecipientsFromMTP(owner, data), | ||||||
|  | 		.noActivityDays = data.vno_activity_days().v, | ||||||
|  | 		.shortcutId = data.vshortcut_id().v, | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
| 
 | 
 | ||||||
| BotInfo::BotInfo() = default; | BotInfo::BotInfo() = default; | ||||||
|  | @ -678,6 +692,8 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) { | ||||||
| 	if (user->isSelf()) { | 	if (user->isSelf()) { | ||||||
| 		user->owner().businessInfo().applyAwaySettings( | 		user->owner().businessInfo().applyAwaySettings( | ||||||
| 			FromMTP(&user->owner(), update.vbusiness_away_message())); | 			FromMTP(&user->owner(), update.vbusiness_away_message())); | ||||||
|  | 		user->owner().businessInfo().applyGreetingSettings( | ||||||
|  | 			FromMTP(&user->owner(), update.vbusiness_greeting_message())); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	user->owner().stories().apply(user, update.vstories()); | 	user->owner().stories().apply(user, update.vstories()); | ||||||
|  |  | ||||||
|  | @ -7,22 +7,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| */ | */ | ||||||
| #include "settings/business/settings_greeting.h" | #include "settings/business/settings_greeting.h" | ||||||
| 
 | 
 | ||||||
|  | #include "base/event_filter.h" | ||||||
| #include "core/application.h" | #include "core/application.h" | ||||||
|  | #include "data/business/data_business_info.h" | ||||||
| #include "data/data_session.h" | #include "data/data_session.h" | ||||||
| #include "lang/lang_keys.h" | #include "lang/lang_keys.h" | ||||||
| #include "main/main_session.h" | #include "main/main_session.h" | ||||||
| #include "settings/business/settings_recipients_helper.h" | #include "settings/business/settings_recipients_helper.h" | ||||||
|  | #include "ui/layers/generic_box.h" | ||||||
| #include "ui/text/text_utilities.h" | #include "ui/text/text_utilities.h" | ||||||
|  | #include "ui/widgets/box_content_divider.h" | ||||||
| #include "ui/widgets/buttons.h" | #include "ui/widgets/buttons.h" | ||||||
|  | #include "ui/widgets/vertical_drum_picker.h" | ||||||
| #include "ui/wrap/slide_wrap.h" | #include "ui/wrap/slide_wrap.h" | ||||||
| #include "ui/wrap/vertical_layout.h" | #include "ui/wrap/vertical_layout.h" | ||||||
| #include "ui/vertical_list.h" | #include "ui/vertical_list.h" | ||||||
| #include "window/window_session_controller.h" | #include "window/window_session_controller.h" | ||||||
|  | #include "styles/style_layers.h" | ||||||
| #include "styles/style_settings.h" | #include "styles/style_settings.h" | ||||||
| 
 | 
 | ||||||
| namespace Settings { | namespace Settings { | ||||||
| namespace { | namespace { | ||||||
| 
 | 
 | ||||||
|  | constexpr auto kDefaultNoActivityDays = 7; | ||||||
|  | 
 | ||||||
| class Greeting : public BusinessSection<Greeting> { | class Greeting : public BusinessSection<Greeting> { | ||||||
| public: | public: | ||||||
| 	Greeting( | 	Greeting( | ||||||
|  | @ -32,21 +40,129 @@ public: | ||||||
| 
 | 
 | ||||||
| 	[[nodiscard]] rpl::producer<QString> title() override; | 	[[nodiscard]] rpl::producer<QString> title() override; | ||||||
| 
 | 
 | ||||||
|  | 	const Ui::RoundRect *bottomSkipRounding() const { | ||||||
|  | 		return &_bottomSkipRounding; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
| 	void setupContent(not_null<Window::SessionController*> controller); | 	void setupContent(not_null<Window::SessionController*> controller); | ||||||
| 	void save(); | 	void save(); | ||||||
| 
 | 
 | ||||||
|  | 	Ui::RoundRect _bottomSkipRounding; | ||||||
|  | 
 | ||||||
| 	rpl::variable<Data::BusinessRecipients> _recipients; | 	rpl::variable<Data::BusinessRecipients> _recipients; | ||||||
|  | 	rpl::variable<int> _noActivityDays; | ||||||
|  | 	rpl::variable<bool> _enabled; | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Greeting::Greeting( | Greeting::Greeting( | ||||||
| 	QWidget *parent, | 	QWidget *parent, | ||||||
| 	not_null<Window::SessionController*> controller) | 	not_null<Window::SessionController*> controller) | ||||||
| : BusinessSection(parent, controller) { | : BusinessSection(parent, controller) | ||||||
|  | , _bottomSkipRounding(st::boxRadius, st::boxDividerBg) { | ||||||
| 	setupContent(controller); | 	setupContent(controller); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void EditPeriodBox( | ||||||
|  | 		not_null<Ui::GenericBox*> box, | ||||||
|  | 		int days, | ||||||
|  | 		Fn<void(int)> save) { | ||||||
|  | 	auto values = base::flat_set<int>{ 7, 14, 21, 28 }; | ||||||
|  | 	if (!values.contains(days)) { | ||||||
|  | 		values.emplace(days); | ||||||
|  | 	} | ||||||
|  | 	const auto startIndex = int(values.find(days) - begin(values)); | ||||||
|  | 
 | ||||||
|  | 	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, | ||||||
|  | 			tr::lng_days(tr::now, lt_count, *(values.begin() + index)), | ||||||
|  | 			style::al_center); | ||||||
|  | 		p.restore(); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	const auto picker = Ui::CreateChild<Ui::VerticalDrumPicker>( | ||||||
|  | 		content, | ||||||
|  | 		std::move(paintCallback), | ||||||
|  | 		int(values.size()), | ||||||
|  | 		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(*(begin(values) + picker->index())); | ||||||
|  | 		if (const auto strong = weak.data()) { | ||||||
|  | 			strong->closeBox(); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | 	box->addButton(tr::lng_cancel(), [=] { | ||||||
|  | 		box->closeBox(); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Greeting::~Greeting() { | Greeting::~Greeting() { | ||||||
| 	if (!Core::Quitting()) { | 	if (!Core::Quitting()) { | ||||||
| 		save(); | 		save(); | ||||||
|  | @ -62,9 +178,14 @@ void Greeting::setupContent( | ||||||
| 	using namespace rpl::mappers; | 	using namespace rpl::mappers; | ||||||
| 
 | 
 | ||||||
| 	const auto content = Ui::CreateChild<Ui::VerticalLayout>(this); | 	const auto content = Ui::CreateChild<Ui::VerticalLayout>(this); | ||||||
| 	//const auto current = controller->session().data().chatbots().current();
 | 	const auto info = &controller->session().data().businessInfo(); | ||||||
|  | 	const auto current = info->greetingSettings(); | ||||||
|  | 	const auto disabled = !current.noActivityDays; | ||||||
| 
 | 
 | ||||||
| 	//_recipients = current.recipients;
 | 	_recipients = current.recipients; | ||||||
|  | 	_noActivityDays = disabled | ||||||
|  | 		? kDefaultNoActivityDays | ||||||
|  | 		: current.noActivityDays; | ||||||
| 
 | 
 | ||||||
| 	AddDividerTextWithLottie(content, { | 	AddDividerTextWithLottie(content, { | ||||||
| 		.lottie = u"greeting"_q, | 		.lottie = u"greeting"_q, | ||||||
|  | @ -80,7 +201,27 @@ void Greeting::setupContent( | ||||||
| 		content, | 		content, | ||||||
| 		tr::lng_greeting_enable(), | 		tr::lng_greeting_enable(), | ||||||
| 		st::settingsButtonNoIcon | 		st::settingsButtonNoIcon | ||||||
| 	))->toggleOn(rpl::single(false)); | 	))->toggleOn(rpl::single(!disabled)); | ||||||
|  | 
 | ||||||
|  | 	_enabled = enabled->toggledValue(); | ||||||
|  | 
 | ||||||
|  | 	Ui::AddSkip(content); | ||||||
|  | 
 | ||||||
|  | 	content->add( | ||||||
|  | 		object_ptr<Ui::SlideWrap<Ui::BoxContentDivider>>( | ||||||
|  | 			content, | ||||||
|  | 			object_ptr<Ui::BoxContentDivider>( | ||||||
|  | 				content, | ||||||
|  | 				st::boxDividerHeight, | ||||||
|  | 				st::boxDividerBg, | ||||||
|  | 				RectPart::Top)) | ||||||
|  | 	)->setDuration(0)->toggleOn(enabled->toggledValue() | rpl::map(!_1)); | ||||||
|  | 	content->add( | ||||||
|  | 		object_ptr<Ui::SlideWrap<Ui::BoxContentDivider>>( | ||||||
|  | 			content, | ||||||
|  | 			object_ptr<Ui::BoxContentDivider>( | ||||||
|  | 				content)) | ||||||
|  | 	)->setDuration(0)->toggleOn(enabled->toggledValue()); | ||||||
| 
 | 
 | ||||||
| 	const auto wrap = content->add( | 	const auto wrap = content->add( | ||||||
| 		object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>( | 		object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>( | ||||||
|  | @ -88,24 +229,50 @@ void Greeting::setupContent( | ||||||
| 			object_ptr<Ui::VerticalLayout>(content))); | 			object_ptr<Ui::VerticalLayout>(content))); | ||||||
| 	const auto inner = wrap->entity(); | 	const auto inner = wrap->entity(); | ||||||
| 
 | 
 | ||||||
| 	Ui::AddSkip(inner); |  | ||||||
| 	Ui::AddDivider(inner); |  | ||||||
| 
 |  | ||||||
| 	wrap->toggleOn(enabled->toggledValue()); |  | ||||||
| 	wrap->finishAnimating(); |  | ||||||
| 
 |  | ||||||
| 	AddBusinessRecipientsSelector(inner, { | 	AddBusinessRecipientsSelector(inner, { | ||||||
| 		.controller = controller, | 		.controller = controller, | ||||||
| 		.title = tr::lng_greeting_recipients(), | 		.title = tr::lng_greeting_recipients(), | ||||||
| 		.data = &_recipients, | 		.data = &_recipients, | ||||||
| 	}); | 	}); | ||||||
| 
 | 
 | ||||||
| 	Ui::AddSkip(inner, st::settingsChatbotsAccessSkip); | 	Ui::AddSkip(inner); | ||||||
|  | 	Ui::AddDivider(inner); | ||||||
|  | 	Ui::AddSkip(inner); | ||||||
|  | 
 | ||||||
|  | 	AddButtonWithLabel( | ||||||
|  | 		inner, | ||||||
|  | 		tr::lng_greeting_period_title(), | ||||||
|  | 		_noActivityDays.value( | ||||||
|  | 		) | rpl::map( | ||||||
|  | 			[](int days) { return tr::lng_days(tr::now, lt_count, days); } | ||||||
|  | 		), | ||||||
|  | 		st::settingsButtonNoIcon | ||||||
|  | 	)->setClickedCallback([=] { | ||||||
|  | 		controller->show(Box( | ||||||
|  | 			EditPeriodBox, | ||||||
|  | 			_noActivityDays.current(), | ||||||
|  | 			[=](int days) { _noActivityDays = days; })); | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  | 	Ui::AddSkip(inner); | ||||||
|  | 	Ui::AddDividerText( | ||||||
|  | 		inner, | ||||||
|  | 		tr::lng_greeting_period_about(), | ||||||
|  | 		st::settingsChatbotsBottomTextMargin, | ||||||
|  | 		RectPart::Top); | ||||||
|  | 
 | ||||||
|  | 	wrap->toggleOn(enabled->toggledValue()); | ||||||
|  | 	wrap->finishAnimating(); | ||||||
| 
 | 
 | ||||||
| 	Ui::ResizeFitChild(this, content); | 	Ui::ResizeFitChild(this, content); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Greeting::save() { | void Greeting::save() { | ||||||
|  | 	controller()->session().data().businessInfo().saveGreetingSettings( | ||||||
|  | 		_enabled.current() ? Data::GreetingSettings{ | ||||||
|  | 			.recipients = _recipients.current(), | ||||||
|  | 			.noActivityDays = _noActivityDays.current(), | ||||||
|  | 		} : Data::GreetingSettings()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 John Preston
						John Preston