1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include "core/core_settings_proxy.h"
11 #include "window/themes/window_themes_embedded.h"
12 #include "ui/chat/attach/attach_send_files_way.h"
13 #include "platform/platform_notifications_manager.h"
14 #include "base/flags.h"
15 #include "emoji.h"
16 
17 enum class RectPart;
18 
19 namespace Ui {
20 enum class InputSubmitSettings;
21 } // namespace Ui
22 
23 namespace Window {
24 enum class Column;
25 } // namespace Window
26 
27 namespace Webrtc {
28 enum class Backend;
29 } // namespace Webrtc
30 
31 namespace Calls::Group {
32 enum class StickedTooltip;
33 } // namespace Calls::Group
34 
35 namespace Core {
36 
37 struct WindowPosition {
38 	WindowPosition() = default;
39 
40 	int32 moncrc = 0;
41 	int maximized = 0;
42 	int scale = 0;
43 	int x = 0;
44 	int y = 0;
45 	int w = 0;
46 	int h = 0;
47 };
48 
49 class Settings final {
50 public:
51 	enum class ScreenCorner {
52 		TopLeft = 0,
53 		TopRight = 1,
54 		BottomRight = 2,
55 		BottomLeft = 3,
56 	};
57 	enum class NotifyView {
58 		ShowPreview = 0,
59 		ShowName = 1,
60 		ShowNothing = 2,
61 	};
62 	enum class WorkMode {
63 		WindowAndTray = 0,
64 		TrayOnly = 1,
65 		WindowOnly = 2,
66 	};
67 
68 	static constexpr auto kDefaultVolume = 0.9;
69 
70 	Settings();
71 
saveDelayedRequests()72 	[[nodiscard]] rpl::producer<> saveDelayedRequests() const {
73 		return _saveDelayed.events();
74 	}
75 
proxy()76 	[[nodiscard]] SettingsProxy &proxy() {
77 		return _proxy;
78 	}
79 
IsLeftCorner(ScreenCorner corner)80 	[[nodiscard]] static bool IsLeftCorner(ScreenCorner corner) {
81 		return (corner == ScreenCorner::TopLeft)
82 			|| (corner == ScreenCorner::BottomLeft);
83 	}
IsTopCorner(ScreenCorner corner)84 	[[nodiscard]] static bool IsTopCorner(ScreenCorner corner) {
85 		return (corner == ScreenCorner::TopLeft)
86 			|| (corner == ScreenCorner::TopRight);
87 	}
88 
89 	[[nodiscard]] QByteArray serialize() const;
90 	void addFromSerialized(const QByteArray &serialized);
91 
adaptiveForWide()92 	[[nodiscard]] bool adaptiveForWide() const {
93 		return _adaptiveForWide.current();
94 	}
adaptiveForWideValue()95 	[[nodiscard]] rpl::producer<bool> adaptiveForWideValue() const {
96 		return _adaptiveForWide.value();
97 	}
adaptiveForWideChanges()98 	[[nodiscard]] rpl::producer<bool> adaptiveForWideChanges() const {
99 		return _adaptiveForWide.changes();
100 	}
setAdaptiveForWide(bool value)101 	void setAdaptiveForWide(bool value) {
102 		_adaptiveForWide = value;
103 	}
moderateModeEnabled()104 	[[nodiscard]] bool moderateModeEnabled() const {
105 		return _moderateModeEnabled;
106 	}
setModerateModeEnabled(bool value)107 	void setModerateModeEnabled(bool value) {
108 		_moderateModeEnabled = value;
109 	}
songVolume()110 	[[nodiscard]] float64 songVolume() const {
111 		return _songVolume.current();
112 	}
songVolumeChanges()113 	[[nodiscard]] rpl::producer<float64> songVolumeChanges() const {
114 		return _songVolume.changes();
115 	}
setSongVolume(float64 value)116 	void setSongVolume(float64 value) {
117 		_songVolume = value;
118 	}
videoVolume()119 	[[nodiscard]] float64 videoVolume() const {
120 		return _videoVolume.current();
121 	}
videoVolumeChanges()122 	[[nodiscard]] rpl::producer<float64> videoVolumeChanges() const {
123 		return _videoVolume.changes();
124 	}
setVideoVolume(float64 value)125 	void setVideoVolume(float64 value) {
126 		_videoVolume = value;
127 	}
askDownloadPath()128 	[[nodiscard]] bool askDownloadPath() const {
129 		return _askDownloadPath;
130 	}
setAskDownloadPath(bool value)131 	void setAskDownloadPath(bool value) {
132 		_askDownloadPath = value;
133 	}
downloadPath()134 	[[nodiscard]] QString downloadPath() const {
135 		return _downloadPath.current();
136 	}
downloadPathValue()137 	[[nodiscard]] rpl::producer<QString> downloadPathValue() const {
138 		return _downloadPath.value();
139 	}
setDownloadPath(const QString & value)140 	void setDownloadPath(const QString &value) {
141 		_downloadPath = value;
142 	}
downloadPathBookmark()143 	[[nodiscard]] QByteArray downloadPathBookmark() const {
144 		return _downloadPathBookmark;
145 	}
setDownloadPathBookmark(const QByteArray & value)146 	void setDownloadPathBookmark(const QByteArray &value) {
147 		_downloadPathBookmark = value;
148 	}
soundNotify()149 	[[nodiscard]] bool soundNotify() const {
150 		return _soundNotify;
151 	}
setSoundNotify(bool value)152 	void setSoundNotify(bool value) {
153 		_soundNotify = value;
154 	}
desktopNotify()155 	[[nodiscard]] bool desktopNotify() const {
156 		return _desktopNotify;
157 	}
setDesktopNotify(bool value)158 	void setDesktopNotify(bool value) {
159 		_desktopNotify = value;
160 	}
flashBounceNotify()161 	[[nodiscard]] bool flashBounceNotify() const {
162 		return _flashBounceNotify;
163 	}
setFlashBounceNotify(bool value)164 	void setFlashBounceNotify(bool value) {
165 		_flashBounceNotify = value;
166 	}
notifyView()167 	[[nodiscard]] NotifyView notifyView() const {
168 		return _notifyView;
169 	}
setNotifyView(NotifyView value)170 	void setNotifyView(NotifyView value) {
171 		_notifyView = value;
172 	}
nativeNotifications()173 	[[nodiscard]] bool nativeNotifications() const {
174 		return _nativeNotifications.value_or(Platform::Notifications::ByDefault());
175 	}
setNativeNotifications(bool value)176 	void setNativeNotifications(bool value) {
177 		_nativeNotifications = (value == Platform::Notifications::ByDefault())
178 			? std::nullopt
179 			: std::make_optional(value);
180 	}
notificationsCount()181 	[[nodiscard]] int notificationsCount() const {
182 		return _notificationsCount;
183 	}
setNotificationsCount(int value)184 	void setNotificationsCount(int value) {
185 		_notificationsCount = value;
186 	}
notificationsCorner()187 	[[nodiscard]] ScreenCorner notificationsCorner() const {
188 		return _notificationsCorner;
189 	}
setNotificationsCorner(ScreenCorner corner)190 	void setNotificationsCorner(ScreenCorner corner) {
191 		_notificationsCorner = corner;
192 	}
includeMutedCounter()193 	[[nodiscard]] bool includeMutedCounter() const {
194 		return _includeMutedCounter;
195 	}
setIncludeMutedCounter(bool value)196 	void setIncludeMutedCounter(bool value) {
197 		_includeMutedCounter = value;
198 	}
countUnreadMessages()199 	[[nodiscard]] bool countUnreadMessages() const {
200 		return _countUnreadMessages;
201 	}
setCountUnreadMessages(bool value)202 	void setCountUnreadMessages(bool value) {
203 		_countUnreadMessages = value;
204 	}
setNotifyAboutPinned(bool notify)205 	void setNotifyAboutPinned(bool notify) {
206 		_notifyAboutPinned = notify;
207 	}
notifyAboutPinned()208 	[[nodiscard]] bool notifyAboutPinned() const {
209 		return _notifyAboutPinned.current();
210 	}
notifyAboutPinnedChanges()211 	[[nodiscard]] rpl::producer<bool> notifyAboutPinnedChanges() const {
212 		return _notifyAboutPinned.changes();
213 	}
autoLock()214 	[[nodiscard]] int autoLock() const {
215 		return _autoLock;
216 	}
setAutoLock(int value)217 	void setAutoLock(int value) {
218 		_autoLock = value;
219 	}
callOutputDeviceId()220 	[[nodiscard]] QString callOutputDeviceId() const {
221 		return _callOutputDeviceId.isEmpty()
222 			? u"default"_q
223 			: _callOutputDeviceId;
224 	}
setCallOutputDeviceId(const QString & value)225 	void setCallOutputDeviceId(const QString &value) {
226 		_callOutputDeviceId = value;
227 	}
callInputDeviceId()228 	[[nodiscard]] QString callInputDeviceId() const {
229 		return _callInputDeviceId.isEmpty()
230 			? u"default"_q
231 			: _callInputDeviceId;
232 	}
setCallInputDeviceId(const QString & value)233 	void setCallInputDeviceId(const QString &value) {
234 		_callInputDeviceId = value;
235 	}
callVideoInputDeviceId()236 	[[nodiscard]] QString callVideoInputDeviceId() const {
237 		return _callVideoInputDeviceId.isEmpty()
238 			? u"default"_q
239 			: _callVideoInputDeviceId;
240 	}
setCallVideoInputDeviceId(const QString & value)241 	void setCallVideoInputDeviceId(const QString &value) {
242 		_callVideoInputDeviceId = value;
243 	}
callOutputVolume()244 	[[nodiscard]] int callOutputVolume() const {
245 		return _callOutputVolume;
246 	}
setCallOutputVolume(int value)247 	void setCallOutputVolume(int value) {
248 		_callOutputVolume = value;
249 	}
callInputVolume()250 	[[nodiscard]] int callInputVolume() const {
251 		return _callInputVolume;
252 	}
setCallInputVolume(int value)253 	void setCallInputVolume(int value) {
254 		_callInputVolume = value;
255 	}
callAudioDuckingEnabled()256 	[[nodiscard]] bool callAudioDuckingEnabled() const {
257 		return _callAudioDuckingEnabled;
258 	}
setCallAudioDuckingEnabled(bool value)259 	void setCallAudioDuckingEnabled(bool value) {
260 		_callAudioDuckingEnabled = value;
261 	}
262 	[[nodiscard]] Webrtc::Backend callAudioBackend() const;
setDisableCalls(bool value)263 	void setDisableCalls(bool value) {
264 		_disableCalls = value;
265 	}
disableCalls()266 	[[nodiscard]] bool disableCalls() const {
267 		return _disableCalls;
268 	}
groupCallPushToTalk()269 	[[nodiscard]] bool groupCallPushToTalk() const {
270 		return _groupCallPushToTalk;
271 	}
setGroupCallPushToTalk(bool value)272 	void setGroupCallPushToTalk(bool value) {
273 		_groupCallPushToTalk = value;
274 	}
groupCallPushToTalkShortcut()275 	[[nodiscard]] QByteArray groupCallPushToTalkShortcut() const {
276 		return _groupCallPushToTalkShortcut;
277 	}
setGroupCallPushToTalkShortcut(const QByteArray & serialized)278 	void setGroupCallPushToTalkShortcut(const QByteArray &serialized) {
279 		_groupCallPushToTalkShortcut = serialized;
280 	}
groupCallPushToTalkDelay()281 	[[nodiscard]] crl::time groupCallPushToTalkDelay() const {
282 		return _groupCallPushToTalkDelay;
283 	}
setGroupCallPushToTalkDelay(crl::time delay)284 	void setGroupCallPushToTalkDelay(crl::time delay) {
285 		_groupCallPushToTalkDelay = delay;
286 	}
groupCallNoiseSuppression()287 	[[nodiscard]] bool groupCallNoiseSuppression() const {
288 		return _groupCallNoiseSuppression;
289 	}
setGroupCallNoiseSuppression(bool value)290 	void setGroupCallNoiseSuppression(bool value) {
291 		_groupCallNoiseSuppression = value;
292 	}
themesAccentColors()293 	[[nodiscard]] Window::Theme::AccentColors &themesAccentColors() {
294 		return _themesAccentColors;
295 	}
setThemesAccentColors(Window::Theme::AccentColors && colors)296 	void setThemesAccentColors(Window::Theme::AccentColors &&colors) {
297 		_themesAccentColors = std::move(colors);
298 	}
setLastSeenWarningSeen(bool lastSeenWarningSeen)299 	void setLastSeenWarningSeen(bool lastSeenWarningSeen) {
300 		_lastSeenWarningSeen = lastSeenWarningSeen;
301 	}
lastSeenWarningSeen()302 	[[nodiscard]] bool lastSeenWarningSeen() const {
303 		return _lastSeenWarningSeen;
304 	}
setSendFilesWay(Ui::SendFilesWay way)305 	void setSendFilesWay(Ui::SendFilesWay way) {
306 		_sendFilesWay = way;
307 	}
sendFilesWay()308 	[[nodiscard]] Ui::SendFilesWay sendFilesWay() const {
309 		return _sendFilesWay;
310 	}
setSendSubmitWay(Ui::InputSubmitSettings value)311 	void setSendSubmitWay(Ui::InputSubmitSettings value) {
312 		_sendSubmitWay = value;
313 	}
sendSubmitWay()314 	[[nodiscard]] Ui::InputSubmitSettings sendSubmitWay() const {
315 		return _sendSubmitWay;
316 	}
setSoundOverride(const QString & key,const QString & path)317 	void setSoundOverride(const QString &key, const QString &path) {
318 		_soundOverrides.emplace(key, path);
319 	}
clearSoundOverrides()320 	void clearSoundOverrides() {
321 		_soundOverrides.clear();
322 	}
323 	[[nodiscard]] QString getSoundPath(const QString &key) const;
324 
exeLaunchWarning()325 	[[nodiscard]] bool exeLaunchWarning() const {
326 		return _exeLaunchWarning;
327 	}
setExeLaunchWarning(bool warning)328 	void setExeLaunchWarning(bool warning) {
329 		_exeLaunchWarning = warning;
330 	}
ipRevealWarning()331 	[[nodiscard]] bool ipRevealWarning() const {
332 		return _ipRevealWarning;
333 	}
setIpRevealWarning(bool warning)334 	void setIpRevealWarning(bool warning) {
335 		_ipRevealWarning = warning;
336 	}
loopAnimatedStickers()337 	[[nodiscard]] bool loopAnimatedStickers() const {
338 		return _loopAnimatedStickers;
339 	}
setLoopAnimatedStickers(bool value)340 	void setLoopAnimatedStickers(bool value) {
341 		_loopAnimatedStickers = value;
342 	}
setLargeEmoji(bool value)343 	void setLargeEmoji(bool value) {
344 		_largeEmoji = value;
345 	}
largeEmoji()346 	[[nodiscard]] bool largeEmoji() const {
347 		return _largeEmoji.current();
348 	}
largeEmojiValue()349 	[[nodiscard]] rpl::producer<bool> largeEmojiValue() const {
350 		return _largeEmoji.value();
351 	}
largeEmojiChanges()352 	[[nodiscard]] rpl::producer<bool> largeEmojiChanges() const {
353 		return _largeEmoji.changes();
354 	}
setReplaceEmoji(bool value)355 	void setReplaceEmoji(bool value) {
356 		_replaceEmoji = value;
357 	}
replaceEmoji()358 	[[nodiscard]] bool replaceEmoji() const {
359 		return _replaceEmoji.current();
360 	}
replaceEmojiValue()361 	[[nodiscard]] rpl::producer<bool> replaceEmojiValue() const {
362 		return _replaceEmoji.value();
363 	}
replaceEmojiChanges()364 	[[nodiscard]] rpl::producer<bool> replaceEmojiChanges() const {
365 		return _replaceEmoji.changes();
366 	}
suggestEmoji()367 	[[nodiscard]] bool suggestEmoji() const {
368 		return _suggestEmoji;
369 	}
setSuggestEmoji(bool value)370 	void setSuggestEmoji(bool value) {
371 		_suggestEmoji = value;
372 	}
suggestStickersByEmoji()373 	[[nodiscard]] bool suggestStickersByEmoji() const {
374 		return _suggestStickersByEmoji;
375 	}
setSuggestStickersByEmoji(bool value)376 	void setSuggestStickersByEmoji(bool value) {
377 		_suggestStickersByEmoji = value;
378 	}
379 
setSpellcheckerEnabled(bool value)380 	void setSpellcheckerEnabled(bool value) {
381 		_spellcheckerEnabled = value;
382 	}
spellcheckerEnabled()383 	bool spellcheckerEnabled() const {
384 		return _spellcheckerEnabled.current();
385 	}
spellcheckerEnabledValue()386 	rpl::producer<bool> spellcheckerEnabledValue() const {
387 		return _spellcheckerEnabled.value();
388 	}
spellcheckerEnabledChanges()389 	rpl::producer<bool> spellcheckerEnabledChanges() const {
390 		return _spellcheckerEnabled.changes();
391 	}
392 
setDictionariesEnabled(std::vector<int> dictionaries)393 	void setDictionariesEnabled(std::vector<int> dictionaries) {
394 		_dictionariesEnabled = std::move(dictionaries);
395 	}
396 
dictionariesEnabled()397 	std::vector<int> dictionariesEnabled() const {
398 		return _dictionariesEnabled.current();
399 	}
400 
dictionariesEnabledChanges()401 	rpl::producer<std::vector<int>> dictionariesEnabledChanges() const {
402 		return _dictionariesEnabled.changes();
403 	}
404 
setAutoDownloadDictionaries(bool value)405 	void setAutoDownloadDictionaries(bool value) {
406 		_autoDownloadDictionaries = value;
407 	}
autoDownloadDictionaries()408 	bool autoDownloadDictionaries() const {
409 		return _autoDownloadDictionaries.current();
410 	}
autoDownloadDictionariesValue()411 	rpl::producer<bool> autoDownloadDictionariesValue() const {
412 		return _autoDownloadDictionaries.value();
413 	}
autoDownloadDictionariesChanges()414 	rpl::producer<bool> autoDownloadDictionariesChanges() const {
415 		return _autoDownloadDictionaries.changes();
416 	}
417 
videoPlaybackSpeed()418 	[[nodiscard]] float64 videoPlaybackSpeed() const {
419 		return _videoPlaybackSpeed.current();
420 	}
setVideoPlaybackSpeed(float64 speed)421 	void setVideoPlaybackSpeed(float64 speed) {
422 		_videoPlaybackSpeed = speed;
423 	}
424 	[[nodiscard]] float64 voicePlaybackSpeed(
425 			bool lastNonDefault = false) const {
426 		return (_nonDefaultVoicePlaybackSpeed || lastNonDefault)
427 			? _voicePlaybackSpeed
428 			: 1.0;
429 	}
setVoicePlaybackSpeed(float64 speed)430 	void setVoicePlaybackSpeed(float64 speed) {
431 		if ((_nonDefaultVoicePlaybackSpeed = (speed != 1.0))) {
432 			_voicePlaybackSpeed = speed;
433 		}
434 	}
videoPipGeometry()435 	[[nodiscard]] QByteArray videoPipGeometry() const {
436 		return _videoPipGeometry;
437 	}
setVideoPipGeometry(QByteArray geometry)438 	void setVideoPipGeometry(QByteArray geometry) {
439 		_videoPipGeometry = geometry;
440 	}
441 
photoEditorBrush()442 	[[nodiscard]] QByteArray photoEditorBrush() const {
443 		return _photoEditorBrush;
444 	}
setPhotoEditorBrush(QByteArray brush)445 	void setPhotoEditorBrush(QByteArray brush) {
446 		_photoEditorBrush = brush;
447 	}
448 
rememberedSongVolume()449 	[[nodiscard]] float64 rememberedSongVolume() const {
450 		return _rememberedSongVolume;
451 	}
setRememberedSongVolume(float64 value)452 	void setRememberedSongVolume(float64 value) {
453 		_rememberedSongVolume = value;
454 	}
rememberedSoundNotifyFromTray()455 	[[nodiscard]] bool rememberedSoundNotifyFromTray() const {
456 		return _rememberedSoundNotifyFromTray;
457 	}
setRememberedSoundNotifyFromTray(bool value)458 	void setRememberedSoundNotifyFromTray(bool value) {
459 		_rememberedSoundNotifyFromTray = value;
460 	}
rememberedFlashBounceNotifyFromTray()461 	[[nodiscard]] bool rememberedFlashBounceNotifyFromTray() const {
462 		return _rememberedFlashBounceNotifyFromTray;
463 	}
setRememberedFlashBounceNotifyFromTray(bool value)464 	void setRememberedFlashBounceNotifyFromTray(bool value) {
465 		_rememberedFlashBounceNotifyFromTray = value;
466 	}
mainMenuAccountsShown()467 	[[nodiscard]] bool mainMenuAccountsShown() const {
468 		return _mainMenuAccountsShown.current();
469 	}
mainMenuAccountsShownValue()470 	[[nodiscard]] rpl::producer<bool> mainMenuAccountsShownValue() const {
471 		return _mainMenuAccountsShown.value();
472 	}
setMainMenuAccountsShown(bool value)473 	void setMainMenuAccountsShown(bool value) {
474 		_mainMenuAccountsShown = value;
475 	}
tabbedSelectorSectionEnabled()476 	[[nodiscard]] bool tabbedSelectorSectionEnabled() const {
477 		return _tabbedSelectorSectionEnabled;
478 	}
479 	void setTabbedSelectorSectionEnabled(bool enabled);
thirdSectionInfoEnabled()480 	[[nodiscard]] bool thirdSectionInfoEnabled() const {
481 		return _thirdSectionInfoEnabled;
482 	}
483 	void setThirdSectionInfoEnabled(bool enabled);
484 	[[nodiscard]] rpl::producer<bool> thirdSectionInfoEnabledValue() const;
thirdSectionExtendedBy()485 	[[nodiscard]] int thirdSectionExtendedBy() const {
486 		return _thirdSectionExtendedBy;
487 	}
setThirdSectionExtendedBy(int savedValue)488 	void setThirdSectionExtendedBy(int savedValue) {
489 		_thirdSectionExtendedBy = savedValue;
490 	}
tabbedReplacedWithInfo()491 	[[nodiscard]] bool tabbedReplacedWithInfo() const {
492 		return _tabbedReplacedWithInfo;
493 	}
494 	void setTabbedReplacedWithInfo(bool enabled);
495 	[[nodiscard]] rpl::producer<bool> tabbedReplacedWithInfoValue() const;
setFloatPlayerColumn(Window::Column column)496 	void setFloatPlayerColumn(Window::Column column) {
497 		_floatPlayerColumn = column;
498 	}
floatPlayerColumn()499 	[[nodiscard]] Window::Column floatPlayerColumn() const {
500 		return _floatPlayerColumn;
501 	}
setFloatPlayerCorner(RectPart corner)502 	void setFloatPlayerCorner(RectPart corner) {
503 		_floatPlayerCorner = corner;
504 	}
floatPlayerCorner()505 	[[nodiscard]] RectPart floatPlayerCorner() const {
506 		return _floatPlayerCorner;
507 	}
508 	void setDialogsWidthRatio(float64 ratio);
509 	[[nodiscard]] float64 dialogsWidthRatio() const;
510 	[[nodiscard]] rpl::producer<float64> dialogsWidthRatioChanges() const;
511 	void setThirdColumnWidth(int width);
512 	[[nodiscard]] int thirdColumnWidth() const;
513 	[[nodiscard]] rpl::producer<int> thirdColumnWidthChanges() const;
setNotifyFromAll(bool value)514 	void setNotifyFromAll(bool value) {
515 		_notifyFromAll = value;
516 	}
notifyFromAll()517 	[[nodiscard]] bool notifyFromAll() const {
518 		return _notifyFromAll;
519 	}
setNativeWindowFrame(bool value)520 	void setNativeWindowFrame(bool value) {
521 		_nativeWindowFrame = value;
522 	}
nativeWindowFrame()523 	[[nodiscard]] bool nativeWindowFrame() const {
524 		return _nativeWindowFrame.current();
525 	}
nativeWindowFrameChanges()526 	[[nodiscard]] rpl::producer<bool> nativeWindowFrameChanges() const {
527 		return _nativeWindowFrame.changes();
528 	}
setSystemDarkMode(std::optional<bool> value)529 	void setSystemDarkMode(std::optional<bool> value) {
530 		_systemDarkMode = value;
531 	}
systemDarkMode()532 	[[nodiscard]] std::optional<bool> systemDarkMode() const {
533 		return _systemDarkMode.current();
534 	}
systemDarkModeValue()535 	[[nodiscard]] rpl::producer<std::optional<bool>> systemDarkModeValue() const {
536 		return _systemDarkMode.value();
537 	}
systemDarkModeChanges()538 	[[nodiscard]] rpl::producer<std::optional<bool>> systemDarkModeChanges() const {
539 		return _systemDarkMode.changes();
540 	}
setSystemDarkModeEnabled(bool value)541 	void setSystemDarkModeEnabled(bool value) {
542 		_systemDarkModeEnabled = value;
543 	}
systemDarkModeEnabled()544 	[[nodiscard]] bool systemDarkModeEnabled() const {
545 		return _systemDarkModeEnabled.current();
546 	}
systemDarkModeEnabledValue()547 	[[nodiscard]] rpl::producer<bool> systemDarkModeEnabledValue() const {
548 		return _systemDarkModeEnabled.value();
549 	}
systemDarkModeEnabledChanges()550 	[[nodiscard]] rpl::producer<bool> systemDarkModeEnabledChanges() const {
551 		return _systemDarkModeEnabled.changes();
552 	}
windowPosition()553 	[[nodiscard]] const WindowPosition &windowPosition() const {
554 		return _windowPosition;
555 	}
setWindowPosition(const WindowPosition & position)556 	void setWindowPosition(const WindowPosition &position) {
557 		_windowPosition = position;
558 	}
setWorkMode(WorkMode value)559 	void setWorkMode(WorkMode value) {
560 		_workMode = value;
561 	}
workMode()562 	[[nodiscard]] WorkMode workMode() const {
563 		return _workMode.current();
564 	}
workModeValue()565 	[[nodiscard]] rpl::producer<WorkMode> workModeValue() const {
566 		return _workMode.value();
567 	}
workModeChanges()568 	[[nodiscard]] rpl::producer<WorkMode> workModeChanges() const {
569 		return _workMode.changes();
570 	}
571 
572 	struct RecentEmoji {
573 		EmojiPtr emoji = nullptr;
574 		ushort rating = 0;
575 	};
576 	[[nodiscard]] const std::vector<RecentEmoji> &recentEmoji() const;
577 	[[nodiscard]] EmojiPack recentEmojiSection() const;
578 	void incrementRecentEmoji(EmojiPtr emoji);
579 	void setLegacyRecentEmojiPreload(QVector<QPair<QString, ushort>> data);
recentEmojiUpdated()580 	[[nodiscard]] rpl::producer<> recentEmojiUpdated() const {
581 		return _recentEmojiUpdated.events();
582 	}
583 
emojiVariants()584 	[[nodiscard]] const base::flat_map<QString, uint8> &emojiVariants() const {
585 		return _emojiVariants;
586 	}
587 	void saveEmojiVariant(EmojiPtr emoji);
588 	void setLegacyEmojiVariants(QMap<QString, int> data);
589 
disableOpenGL()590 	[[nodiscard]] bool disableOpenGL() const {
591 		return _disableOpenGL;
592 	}
setDisableOpenGL(bool value)593 	void setDisableOpenGL(bool value) {
594 		_disableOpenGL = value;
595 	}
596 
hiddenGroupCallTooltips()597 	[[nodiscard]] base::flags<Calls::Group::StickedTooltip> hiddenGroupCallTooltips() const {
598 		return _hiddenGroupCallTooltips;
599 	}
setHiddenGroupCallTooltip(Calls::Group::StickedTooltip value)600 	void setHiddenGroupCallTooltip(Calls::Group::StickedTooltip value) {
601 		_hiddenGroupCallTooltips |= value;
602 	}
603 
setCloseToTaskbar(bool value)604 	void setCloseToTaskbar(bool value) {
605 		_closeToTaskbar = value;
606 	}
closeToTaskbar()607 	[[nodiscard]] bool closeToTaskbar() const {
608 		return _closeToTaskbar.current();
609 	}
closeToTaskbarValue()610 	[[nodiscard]] rpl::producer<bool> closeToTaskbarValue() const {
611 		return _closeToTaskbar.value();
612 	}
closeToTaskbarChanges()613 	[[nodiscard]] rpl::producer<bool> closeToTaskbarChanges() const {
614 		return _closeToTaskbar.changes();
615 	}
616 
617 	[[nodiscard]] static bool ThirdColumnByDefault();
618 	[[nodiscard]] static float64 DefaultDialogsWidthRatio();
SerializePlaybackSpeed(float64 speed)619 	[[nodiscard]] static qint32 SerializePlaybackSpeed(float64 speed) {
620 		return int(base::SafeRound(std::clamp(speed, 0.5, 2.0) * 100));
621 	}
DeserializePlaybackSpeed(qint32 speed)622 	[[nodiscard]] static float64 DeserializePlaybackSpeed(qint32 speed) {
623 		if (speed < 10) {
624 			// The old values in settings.
625 			return (std::clamp(speed, 0, 6) + 2) / 4.;
626 		} else {
627 			return std::clamp(speed, 50, 200) / 100.;
628 		}
629 	}
630 
631 	void resetOnLastLogout();
632 
633 private:
634 	void resolveRecentEmoji() const;
635 
636 	static constexpr auto kDefaultThirdColumnWidth = 0;
637 	static constexpr auto kDefaultDialogsWidthRatio = 5. / 14;
638 	static constexpr auto kDefaultBigDialogsWidthRatio = 0.275;
639 
640 	struct RecentEmojiId {
641 		QString emoji;
642 		ushort rating = 0;
643 	};
644 
645 	SettingsProxy _proxy;
646 
647 	rpl::variable<bool> _adaptiveForWide = true;
648 	bool _moderateModeEnabled = false;
649 	rpl::variable<float64> _songVolume = kDefaultVolume;
650 	rpl::variable<float64> _videoVolume = kDefaultVolume;
651 	bool _askDownloadPath = false;
652 	rpl::variable<QString> _downloadPath;
653 	QByteArray _downloadPathBookmark;
654 	bool _soundNotify = true;
655 	bool _desktopNotify = true;
656 	bool _flashBounceNotify = true;
657 	NotifyView _notifyView = NotifyView::ShowPreview;
658 	std::optional<bool> _nativeNotifications;
659 	int _notificationsCount = 3;
660 	ScreenCorner _notificationsCorner = ScreenCorner::BottomRight;
661 	bool _includeMutedCounter = true;
662 	bool _countUnreadMessages = true;
663 	rpl::variable<bool> _notifyAboutPinned = true;
664 	int _autoLock = 3600;
665 	QString _callOutputDeviceId = u"default"_q;
666 	QString _callInputDeviceId = u"default"_q;
667 	QString _callVideoInputDeviceId = u"default"_q;
668 	int _callOutputVolume = 100;
669 	int _callInputVolume = 100;
670 	bool _callAudioDuckingEnabled = true;
671 	bool _disableCalls = false;
672 	bool _groupCallPushToTalk = false;
673 	bool _groupCallNoiseSuppression = false;
674 	QByteArray _groupCallPushToTalkShortcut;
675 	crl::time _groupCallPushToTalkDelay = 20;
676 	Window::Theme::AccentColors _themesAccentColors;
677 	bool _lastSeenWarningSeen = false;
678 	Ui::SendFilesWay _sendFilesWay = Ui::SendFilesWay();
679 	Ui::InputSubmitSettings _sendSubmitWay = Ui::InputSubmitSettings();
680 	base::flat_map<QString, QString> _soundOverrides;
681 	bool _exeLaunchWarning = true;
682 	bool _ipRevealWarning = true;
683 	bool _loopAnimatedStickers = true;
684 	rpl::variable<bool> _largeEmoji = true;
685 	rpl::variable<bool> _replaceEmoji = true;
686 	bool _suggestEmoji = true;
687 	bool _suggestStickersByEmoji = true;
688 	rpl::variable<bool> _spellcheckerEnabled = true;
689 	rpl::variable<float64> _videoPlaybackSpeed = 1.;
690 	float64 _voicePlaybackSpeed = 2.;
691 	bool _nonDefaultVoicePlaybackSpeed = false;
692 	QByteArray _videoPipGeometry;
693 	rpl::variable<std::vector<int>> _dictionariesEnabled;
694 	rpl::variable<bool> _autoDownloadDictionaries = true;
695 	rpl::variable<bool> _mainMenuAccountsShown = true;
696 	mutable std::vector<RecentEmojiId> _recentEmojiPreload;
697 	mutable std::vector<RecentEmoji> _recentEmoji;
698 	base::flat_map<QString, uint8> _emojiVariants;
699 	rpl::event_stream<> _recentEmojiUpdated;
700 	bool _tabbedSelectorSectionEnabled = false; // per-window
701 	Window::Column _floatPlayerColumn = Window::Column(); // per-window
702 	RectPart _floatPlayerCorner = RectPart(); // per-window
703 	bool _thirdSectionInfoEnabled = true; // per-window
704 	rpl::event_stream<bool> _thirdSectionInfoEnabledValue; // per-window
705 	int _thirdSectionExtendedBy = -1; // per-window
706 	rpl::variable<float64> _dialogsWidthRatio; // per-window
707 	rpl::variable<int> _thirdColumnWidth = kDefaultThirdColumnWidth; // p-w
708 	bool _notifyFromAll = true;
709 	rpl::variable<bool> _nativeWindowFrame = false;
710 	rpl::variable<std::optional<bool>> _systemDarkMode = std::nullopt;
711 	rpl::variable<bool> _systemDarkModeEnabled = false;
712 	WindowPosition _windowPosition; // per-window
713 	bool _disableOpenGL = false;
714 	rpl::variable<WorkMode> _workMode = WorkMode::WindowAndTray;
715 	base::flags<Calls::Group::StickedTooltip> _hiddenGroupCallTooltips;
716 	rpl::variable<bool> _closeToTaskbar = false;
717 
718 	bool _tabbedReplacedWithInfo = false; // per-window
719 	rpl::event_stream<bool> _tabbedReplacedWithInfoValue; // per-window
720 
721 	rpl::event_stream<> _saveDelayed;
722 	float64 _rememberedSongVolume = kDefaultVolume;
723 	bool _rememberedSoundNotifyFromTray = false;
724 	bool _rememberedFlashBounceNotifyFromTray = false;
725 
726 	QByteArray _photoEditorBrush;
727 
728 };
729 
730 } // namespace Core
731 
732