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 #include "core/core_settings.h"
9
10 #include "boxes/send_files_box.h"
11 #include "ui/widgets/input_fields.h"
12 #include "storage/serialize_common.h"
13 #include "window/section_widget.h"
14 #include "base/platform/base_platform_info.h"
15 #include "webrtc/webrtc_create_adm.h"
16 #include "ui/gl/gl_detection.h"
17 #include "calls/group/calls_group_common.h"
18 #include "facades.h"
19
20 namespace Core {
21 namespace {
22
23 constexpr auto kRecentEmojiLimit = 42;
24
Deserialize(const QByteArray & data)25 [[nodiscard]] WindowPosition Deserialize(const QByteArray &data) {
26 QDataStream stream(data);
27 stream.setVersion(QDataStream::Qt_5_1);
28
29 auto result = WindowPosition();
30 stream
31 >> result.x
32 >> result.y
33 >> result.w
34 >> result.h
35 >> result.moncrc
36 >> result.maximized
37 >> result.scale;
38 return result;
39 }
40
Serialize(const WindowPosition & position)41 [[nodiscard]] QByteArray Serialize(const WindowPosition &position) {
42 auto result = QByteArray();
43 const auto size = 7 * sizeof(qint32);
44 result.reserve(size);
45 {
46 QDataStream stream(&result, QIODevice::WriteOnly);
47 stream.setVersion(QDataStream::Qt_5_1);
48 stream
49 << qint32(position.x)
50 << qint32(position.y)
51 << qint32(position.w)
52 << qint32(position.h)
53 << qint32(position.moncrc)
54 << qint32(position.maximized)
55 << qint32(position.scale);
56 }
57 DEBUG_LOG(("Window Pos: Writing to storage %1, %2, %3, %4"
58 " (scale %5%, maximized %6)")
59 .arg(position.x)
60 .arg(position.y)
61 .arg(position.w)
62 .arg(position.h)
63 .arg(position.scale)
64 .arg(Logs::b(position.maximized)));
65 return result;
66 }
67
68 } // namespace
69
Settings()70 Settings::Settings()
71 : _sendSubmitWay(Ui::InputSubmitSettings::Enter)
72 , _floatPlayerColumn(Window::Column::Second)
73 , _floatPlayerCorner(RectPart::TopRight)
74 , _dialogsWidthRatio(DefaultDialogsWidthRatio()) {
75 }
76
serialize() const77 QByteArray Settings::serialize() const {
78 const auto themesAccentColors = _themesAccentColors.serialize();
79 const auto windowPosition = Serialize(_windowPosition);
80 const auto proxy = _proxy.serialize();
81
82 auto recentEmojiPreloadGenerated = std::vector<RecentEmojiId>();
83 if (_recentEmojiPreload.empty()) {
84 recentEmojiPreloadGenerated.reserve(_recentEmoji.size());
85 for (const auto &[emoji, rating] : _recentEmoji) {
86 recentEmojiPreloadGenerated.push_back({ emoji->id(), rating });
87 }
88 }
89 const auto &recentEmojiPreloadData = _recentEmojiPreload.empty()
90 ? recentEmojiPreloadGenerated
91 : _recentEmojiPreload;
92
93 auto size = Serialize::bytearraySize(themesAccentColors)
94 + sizeof(qint32) * 5
95 + Serialize::stringSize(_downloadPath.current())
96 + Serialize::bytearraySize(_downloadPathBookmark)
97 + sizeof(qint32) * 9
98 + Serialize::stringSize(_callOutputDeviceId)
99 + Serialize::stringSize(_callInputDeviceId)
100 + sizeof(qint32) * 5;
101 for (const auto &[key, value] : _soundOverrides) {
102 size += Serialize::stringSize(key) + Serialize::stringSize(value);
103 }
104 size += sizeof(qint32) * 13
105 + Serialize::bytearraySize(_videoPipGeometry)
106 + sizeof(qint32)
107 + (_dictionariesEnabled.current().size() * sizeof(quint64))
108 + sizeof(qint32) * 12
109 + Serialize::stringSize(_callVideoInputDeviceId)
110 + sizeof(qint32) * 2
111 + Serialize::bytearraySize(_groupCallPushToTalkShortcut)
112 + sizeof(qint64)
113 + sizeof(qint32) * 2
114 + Serialize::bytearraySize(windowPosition)
115 + sizeof(qint32);
116 for (const auto &[id, rating] : recentEmojiPreloadData) {
117 size += Serialize::stringSize(id) + sizeof(quint16);
118 }
119 size += sizeof(qint32);
120 for (const auto &[id, variant] : _emojiVariants) {
121 size += Serialize::stringSize(id) + sizeof(quint8);
122 }
123 size += sizeof(qint32) * 3
124 + Serialize::bytearraySize(proxy)
125 + sizeof(qint32) * 2
126 + Serialize::bytearraySize(_photoEditorBrush)
127 + sizeof(qint32);
128
129 auto result = QByteArray();
130 result.reserve(size);
131 {
132 QDataStream stream(&result, QIODevice::WriteOnly);
133 stream.setVersion(QDataStream::Qt_5_1);
134 stream
135 << themesAccentColors
136 << qint32(_adaptiveForWide.current() ? 1 : 0)
137 << qint32(_moderateModeEnabled ? 1 : 0)
138 << qint32(qRound(_songVolume.current() * 1e6))
139 << qint32(qRound(_videoVolume.current() * 1e6))
140 << qint32(_askDownloadPath ? 1 : 0)
141 << _downloadPath.current()
142 << _downloadPathBookmark
143 << qint32(_nonDefaultVoicePlaybackSpeed ? 1 : 0)
144 << qint32(_soundNotify ? 1 : 0)
145 << qint32(_desktopNotify ? 1 : 0)
146 << qint32(_flashBounceNotify ? 1 : 0)
147 << static_cast<qint32>(_notifyView)
148 << qint32(_nativeNotifications ? (*_nativeNotifications ? 1 : 2) : 0)
149 << qint32(_notificationsCount)
150 << static_cast<qint32>(_notificationsCorner)
151 << qint32(_autoLock)
152 << _callOutputDeviceId
153 << _callInputDeviceId
154 << qint32(_callOutputVolume)
155 << qint32(_callInputVolume)
156 << qint32(_callAudioDuckingEnabled ? 1 : 0)
157 << qint32(_lastSeenWarningSeen ? 1 : 0)
158 << qint32(_soundOverrides.size());
159 for (const auto &[key, value] : _soundOverrides) {
160 stream << key << value;
161 }
162 stream
163 << qint32(_sendFilesWay.serialize())
164 << qint32(_sendSubmitWay)
165 << qint32(_includeMutedCounter ? 1 : 0)
166 << qint32(_countUnreadMessages ? 1 : 0)
167 << qint32(_exeLaunchWarning ? 1 : 0)
168 << qint32(_notifyAboutPinned.current() ? 1 : 0)
169 << qint32(_loopAnimatedStickers ? 1 : 0)
170 << qint32(_largeEmoji.current() ? 1 : 0)
171 << qint32(_replaceEmoji.current() ? 1 : 0)
172 << qint32(_suggestEmoji ? 1 : 0)
173 << qint32(_suggestStickersByEmoji ? 1 : 0)
174 << qint32(_spellcheckerEnabled.current() ? 1 : 0)
175 << qint32(SerializePlaybackSpeed(_videoPlaybackSpeed.current()))
176 << _videoPipGeometry
177 << qint32(_dictionariesEnabled.current().size());
178 for (const auto i : _dictionariesEnabled.current()) {
179 stream << quint64(i);
180 }
181 stream
182 << qint32(_autoDownloadDictionaries.current() ? 1 : 0)
183 << qint32(_mainMenuAccountsShown.current() ? 1 : 0)
184 << qint32(_tabbedSelectorSectionEnabled ? 1 : 0)
185 << qint32(_floatPlayerColumn)
186 << qint32(_floatPlayerCorner)
187 << qint32(_thirdSectionInfoEnabled ? 1 : 0)
188 << qint32(std::clamp(
189 qRound(_dialogsWidthRatio.current() * 1000000),
190 0,
191 1000000))
192 << qint32(_thirdColumnWidth.current())
193 << qint32(_thirdSectionExtendedBy)
194 << qint32(_notifyFromAll ? 1 : 0)
195 << qint32(_nativeWindowFrame.current() ? 1 : 0)
196 << qint32(_systemDarkModeEnabled.current() ? 1 : 0)
197 << _callVideoInputDeviceId
198 << qint32(_ipRevealWarning ? 1 : 0)
199 << qint32(_groupCallPushToTalk ? 1 : 0)
200 << _groupCallPushToTalkShortcut
201 << qint64(_groupCallPushToTalkDelay)
202 << qint32(0) // Call audio backend
203 << qint32(_disableCalls ? 1 : 0)
204 << windowPosition
205 << qint32(recentEmojiPreloadData.size());
206 for (const auto &[id, rating] : recentEmojiPreloadData) {
207 stream << id << quint16(rating);
208 }
209 stream
210 << qint32(_emojiVariants.size());
211 for (const auto &[id, variant] : _emojiVariants) {
212 stream << id << quint8(variant);
213 }
214 stream
215 << qint32(0) // Old Disable OpenGL
216 << qint32(0) // Old Noise Suppression
217 << qint32(_workMode.current())
218 << proxy
219 << qint32(_hiddenGroupCallTooltips.value())
220 << qint32(_disableOpenGL ? 1 : 0)
221 << _photoEditorBrush
222 << qint32(_groupCallNoiseSuppression ? 1 : 0)
223 << qint32(_voicePlaybackSpeed * 100)
224 << qint32(_closeToTaskbar.current() ? 1 : 0);
225 }
226 return result;
227 }
228
addFromSerialized(const QByteArray & serialized)229 void Settings::addFromSerialized(const QByteArray &serialized) {
230 if (serialized.isEmpty()) {
231 return;
232 }
233
234 QDataStream stream(serialized);
235 stream.setVersion(QDataStream::Qt_5_1);
236
237 QByteArray themesAccentColors;
238 qint32 adaptiveForWide = _adaptiveForWide.current() ? 1 : 0;
239 qint32 moderateModeEnabled = _moderateModeEnabled ? 1 : 0;
240 qint32 songVolume = qint32(qRound(_songVolume.current() * 1e6));
241 qint32 videoVolume = qint32(qRound(_videoVolume.current() * 1e6));
242 qint32 askDownloadPath = _askDownloadPath ? 1 : 0;
243 QString downloadPath = _downloadPath.current();
244 QByteArray downloadPathBookmark = _downloadPathBookmark;
245 qint32 nonDefaultVoicePlaybackSpeed = _nonDefaultVoicePlaybackSpeed ? 1 : 0;
246 qint32 soundNotify = _soundNotify ? 1 : 0;
247 qint32 desktopNotify = _desktopNotify ? 1 : 0;
248 qint32 flashBounceNotify = _flashBounceNotify ? 1 : 0;
249 qint32 notifyView = static_cast<qint32>(_notifyView);
250 qint32 nativeNotifications = _nativeNotifications ? (*_nativeNotifications ? 1 : 2) : 0;
251 qint32 notificationsCount = _notificationsCount;
252 qint32 notificationsCorner = static_cast<qint32>(_notificationsCorner);
253 qint32 autoLock = _autoLock;
254 QString callOutputDeviceId = _callOutputDeviceId;
255 QString callInputDeviceId = _callInputDeviceId;
256 QString callVideoInputDeviceId = _callVideoInputDeviceId;
257 qint32 callOutputVolume = _callOutputVolume;
258 qint32 callInputVolume = _callInputVolume;
259 qint32 callAudioDuckingEnabled = _callAudioDuckingEnabled ? 1 : 0;
260 qint32 lastSeenWarningSeen = _lastSeenWarningSeen ? 1 : 0;
261 qint32 soundOverridesCount = 0;
262 base::flat_map<QString, QString> soundOverrides;
263 qint32 sendFilesWay = _sendFilesWay.serialize();
264 qint32 sendSubmitWay = static_cast<qint32>(_sendSubmitWay);
265 qint32 includeMutedCounter = _includeMutedCounter ? 1 : 0;
266 qint32 countUnreadMessages = _countUnreadMessages ? 1 : 0;
267 qint32 exeLaunchWarning = _exeLaunchWarning ? 1 : 0;
268 qint32 notifyAboutPinned = _notifyAboutPinned.current() ? 1 : 0;
269 qint32 loopAnimatedStickers = _loopAnimatedStickers ? 1 : 0;
270 qint32 largeEmoji = _largeEmoji.current() ? 1 : 0;
271 qint32 replaceEmoji = _replaceEmoji.current() ? 1 : 0;
272 qint32 suggestEmoji = _suggestEmoji ? 1 : 0;
273 qint32 suggestStickersByEmoji = _suggestStickersByEmoji ? 1 : 0;
274 qint32 spellcheckerEnabled = _spellcheckerEnabled.current() ? 1 : 0;
275 qint32 videoPlaybackSpeed = Core::Settings::SerializePlaybackSpeed(_videoPlaybackSpeed.current());
276 qint32 voicePlaybackSpeed = _voicePlaybackSpeed * 100;
277 QByteArray videoPipGeometry = _videoPipGeometry;
278 qint32 dictionariesEnabledCount = 0;
279 std::vector<int> dictionariesEnabled;
280 qint32 autoDownloadDictionaries = _autoDownloadDictionaries.current() ? 1 : 0;
281 qint32 mainMenuAccountsShown = _mainMenuAccountsShown.current() ? 1 : 0;
282 qint32 tabbedSelectorSectionEnabled = 1;
283 qint32 floatPlayerColumn = static_cast<qint32>(Window::Column::Second);
284 qint32 floatPlayerCorner = static_cast<qint32>(RectPart::TopRight);
285 qint32 thirdSectionInfoEnabled = 0;
286 float64 dialogsWidthRatio = _dialogsWidthRatio.current();
287 qint32 thirdColumnWidth = _thirdColumnWidth.current();
288 qint32 thirdSectionExtendedBy = _thirdSectionExtendedBy;
289 qint32 notifyFromAll = _notifyFromAll ? 1 : 0;
290 qint32 nativeWindowFrame = _nativeWindowFrame.current() ? 1 : 0;
291 qint32 systemDarkModeEnabled = _systemDarkModeEnabled.current() ? 1 : 0;
292 qint32 ipRevealWarning = _ipRevealWarning ? 1 : 0;
293 qint32 groupCallPushToTalk = _groupCallPushToTalk ? 1 : 0;
294 QByteArray groupCallPushToTalkShortcut = _groupCallPushToTalkShortcut;
295 qint64 groupCallPushToTalkDelay = _groupCallPushToTalkDelay;
296 qint32 callAudioBackend = 0;
297 qint32 disableCalls = _disableCalls ? 1 : 0;
298 QByteArray windowPosition;
299 std::vector<RecentEmojiId> recentEmojiPreload;
300 base::flat_map<QString, uint8> emojiVariants;
301 qint32 disableOpenGL = _disableOpenGL ? 1 : 0;
302 qint32 groupCallNoiseSuppression = _groupCallNoiseSuppression ? 1 : 0;
303 qint32 workMode = static_cast<qint32>(_workMode.current());
304 QByteArray proxy;
305 qint32 hiddenGroupCallTooltips = qint32(_hiddenGroupCallTooltips.value());
306 QByteArray photoEditorBrush = _photoEditorBrush;
307 qint32 closeToTaskbar = _closeToTaskbar.current() ? 1 : 0;
308
309 stream >> themesAccentColors;
310 if (!stream.atEnd()) {
311 stream
312 >> adaptiveForWide
313 >> moderateModeEnabled
314 >> songVolume
315 >> videoVolume
316 >> askDownloadPath
317 >> downloadPath
318 >> downloadPathBookmark
319 >> nonDefaultVoicePlaybackSpeed
320 >> soundNotify
321 >> desktopNotify
322 >> flashBounceNotify
323 >> notifyView
324 >> nativeNotifications
325 >> notificationsCount
326 >> notificationsCorner
327 >> autoLock
328 >> callOutputDeviceId
329 >> callInputDeviceId
330 >> callOutputVolume
331 >> callInputVolume
332 >> callAudioDuckingEnabled
333 >> lastSeenWarningSeen
334 >> soundOverridesCount;
335 if (stream.status() == QDataStream::Ok) {
336 for (auto i = 0; i != soundOverridesCount; ++i) {
337 QString key, value;
338 stream >> key >> value;
339 soundOverrides.emplace(key, value);
340 }
341 }
342 stream
343 >> sendFilesWay
344 >> sendSubmitWay
345 >> includeMutedCounter
346 >> countUnreadMessages
347 >> exeLaunchWarning
348 >> notifyAboutPinned
349 >> loopAnimatedStickers
350 >> largeEmoji
351 >> replaceEmoji
352 >> suggestEmoji
353 >> suggestStickersByEmoji
354 >> spellcheckerEnabled
355 >> videoPlaybackSpeed
356 >> videoPipGeometry
357 >> dictionariesEnabledCount;
358 if (stream.status() == QDataStream::Ok) {
359 for (auto i = 0; i != dictionariesEnabledCount; ++i) {
360 qint64 langId;
361 stream >> langId;
362 dictionariesEnabled.emplace_back(langId);
363 }
364 }
365 stream
366 >> autoDownloadDictionaries
367 >> mainMenuAccountsShown;
368 }
369 if (!stream.atEnd()) {
370 auto dialogsWidthRatioInt = qint32();
371 stream
372 >> tabbedSelectorSectionEnabled
373 >> floatPlayerColumn
374 >> floatPlayerCorner
375 >> thirdSectionInfoEnabled
376 >> dialogsWidthRatioInt
377 >> thirdColumnWidth
378 >> thirdSectionExtendedBy
379 >> notifyFromAll;
380 dialogsWidthRatio = std::clamp(
381 dialogsWidthRatioInt / 1000000.,
382 0.,
383 1.);
384 }
385 if (!stream.atEnd()) {
386 stream >> nativeWindowFrame;
387 }
388 if (!stream.atEnd()) {
389 stream >> systemDarkModeEnabled;
390 }
391 if (!stream.atEnd()) {
392 stream >> callVideoInputDeviceId;
393 }
394 if (!stream.atEnd()) {
395 stream >> ipRevealWarning;
396 }
397 if (!stream.atEnd()) {
398 stream
399 >> groupCallPushToTalk
400 >> groupCallPushToTalkShortcut
401 >> groupCallPushToTalkDelay;
402 }
403 if (!stream.atEnd()) {
404 stream >> callAudioBackend;
405 }
406 if (!stream.atEnd()) {
407 stream >> disableCalls;
408 }
409 if (!stream.atEnd()) {
410 stream >> windowPosition;
411 }
412 if (!stream.atEnd()) {
413 auto recentCount = qint32(0);
414 stream >> recentCount;
415 if (recentCount > 0 && recentCount < 10000) {
416 recentEmojiPreload.reserve(recentCount);
417 for (auto i = 0; i != recentCount; ++i) {
418 auto id = QString();
419 auto rating = quint16();
420 stream >> id >> rating;
421 recentEmojiPreload.push_back({ id, rating });
422 }
423 }
424 auto variantsCount = qint32(0);
425 stream >> variantsCount;
426 if (variantsCount > 0 && variantsCount < 10000) {
427 emojiVariants.reserve(variantsCount);
428 for (auto i = 0; i != variantsCount; ++i) {
429 auto id = QString();
430 auto variant = quint8();
431 stream >> id >> variant;
432 emojiVariants.emplace(id, variant);
433 }
434 }
435 }
436 if (!stream.atEnd()) {
437 qint32 disableOpenGLOld;
438 stream >> disableOpenGLOld;
439 }
440 if (!stream.atEnd()) {
441 qint32 groupCallNoiseSuppressionOld;
442 stream >> groupCallNoiseSuppressionOld;
443 }
444 if (!stream.atEnd()) {
445 stream >> workMode;
446 }
447 if (!stream.atEnd()) {
448 stream >> proxy;
449 }
450 if (!stream.atEnd()) {
451 stream >> hiddenGroupCallTooltips;
452 }
453 if (!stream.atEnd()) {
454 stream >> disableOpenGL;
455 }
456 if (!stream.atEnd()) {
457 stream >> photoEditorBrush;
458 }
459 if (!stream.atEnd()) {
460 stream >> groupCallNoiseSuppression;
461 }
462 if (!stream.atEnd()) {
463 stream >> voicePlaybackSpeed;
464 }
465 if (!stream.atEnd()) {
466 stream >> closeToTaskbar;
467 }
468 if (stream.status() != QDataStream::Ok) {
469 LOG(("App Error: "
470 "Bad data for Core::Settings::constructFromSerialized()"));
471 return;
472 } else if (!_themesAccentColors.setFromSerialized(themesAccentColors)) {
473 return;
474 } else if (!_proxy.setFromSerialized(proxy)) {
475 return;
476 }
477 _adaptiveForWide = (adaptiveForWide == 1);
478 _moderateModeEnabled = (moderateModeEnabled == 1);
479 _songVolume = std::clamp(songVolume / 1e6, 0., 1.);
480 _videoVolume = std::clamp(videoVolume / 1e6, 0., 1.);
481 _askDownloadPath = (askDownloadPath == 1);
482 _downloadPath = downloadPath;
483 _downloadPathBookmark = downloadPathBookmark;
484 _soundNotify = (soundNotify == 1);
485 _desktopNotify = (desktopNotify == 1);
486 _flashBounceNotify = (flashBounceNotify == 1);
487 const auto uncheckedNotifyView = static_cast<NotifyView>(notifyView);
488 switch (uncheckedNotifyView) {
489 case NotifyView::ShowNothing:
490 case NotifyView::ShowName:
491 case NotifyView::ShowPreview: _notifyView = uncheckedNotifyView; break;
492 }
493 switch (nativeNotifications) {
494 case 0: _nativeNotifications = std::nullopt; break;
495 case 1: _nativeNotifications = true; break;
496 case 2: _nativeNotifications = false; break;
497 default: break;
498 }
499 _notificationsCount = (notificationsCount > 0) ? notificationsCount : 3;
500 const auto uncheckedNotificationsCorner = static_cast<ScreenCorner>(notificationsCorner);
501 switch (uncheckedNotificationsCorner) {
502 case ScreenCorner::TopLeft:
503 case ScreenCorner::TopRight:
504 case ScreenCorner::BottomRight:
505 case ScreenCorner::BottomLeft: _notificationsCorner = uncheckedNotificationsCorner; break;
506 }
507 _includeMutedCounter = (includeMutedCounter == 1);
508 _countUnreadMessages = (countUnreadMessages == 1);
509 _notifyAboutPinned = (notifyAboutPinned == 1);
510 _autoLock = autoLock;
511 _callOutputDeviceId = callOutputDeviceId;
512 _callInputDeviceId = callInputDeviceId;
513 _callVideoInputDeviceId = callVideoInputDeviceId;
514 _callOutputVolume = callOutputVolume;
515 _callInputVolume = callInputVolume;
516 _callAudioDuckingEnabled = (callAudioDuckingEnabled == 1);
517 _lastSeenWarningSeen = (lastSeenWarningSeen == 1);
518 _soundOverrides = std::move(soundOverrides);
519 _sendFilesWay = Ui::SendFilesWay::FromSerialized(sendFilesWay).value_or(_sendFilesWay);
520 auto uncheckedSendSubmitWay = static_cast<Ui::InputSubmitSettings>(sendSubmitWay);
521 switch (uncheckedSendSubmitWay) {
522 case Ui::InputSubmitSettings::Enter:
523 case Ui::InputSubmitSettings::CtrlEnter: _sendSubmitWay = uncheckedSendSubmitWay; break;
524 }
525 _includeMutedCounter = (includeMutedCounter == 1);
526 _countUnreadMessages = (countUnreadMessages == 1);
527 _exeLaunchWarning = (exeLaunchWarning == 1);
528 _ipRevealWarning = (ipRevealWarning == 1);
529 _notifyAboutPinned = (notifyAboutPinned == 1);
530 _loopAnimatedStickers = (loopAnimatedStickers == 1);
531 _largeEmoji = (largeEmoji == 1);
532 _replaceEmoji = (replaceEmoji == 1);
533 _suggestEmoji = (suggestEmoji == 1);
534 _suggestStickersByEmoji = (suggestStickersByEmoji == 1);
535 _spellcheckerEnabled = (spellcheckerEnabled == 1);
536 _videoPlaybackSpeed = DeserializePlaybackSpeed(videoPlaybackSpeed);
537 {
538 // Restore settings from 3.0.1 version.
539 if (voicePlaybackSpeed == 100) {
540 _nonDefaultVoicePlaybackSpeed = false;
541 _voicePlaybackSpeed = 2.0;
542 } else {
543 _nonDefaultVoicePlaybackSpeed =
544 (nonDefaultVoicePlaybackSpeed == 1);
545 _voicePlaybackSpeed = voicePlaybackSpeed / 100.;
546 }
547 }
548 _videoPipGeometry = (videoPipGeometry);
549 _dictionariesEnabled = std::move(dictionariesEnabled);
550 _autoDownloadDictionaries = (autoDownloadDictionaries == 1);
551 _mainMenuAccountsShown = (mainMenuAccountsShown == 1);
552 _tabbedSelectorSectionEnabled = (tabbedSelectorSectionEnabled == 1);
553 auto uncheckedColumn = static_cast<Window::Column>(floatPlayerColumn);
554 switch (uncheckedColumn) {
555 case Window::Column::First:
556 case Window::Column::Second:
557 case Window::Column::Third: _floatPlayerColumn = uncheckedColumn; break;
558 }
559 auto uncheckedCorner = static_cast<RectPart>(floatPlayerCorner);
560 switch (uncheckedCorner) {
561 case RectPart::TopLeft:
562 case RectPart::TopRight:
563 case RectPart::BottomLeft:
564 case RectPart::BottomRight: _floatPlayerCorner = uncheckedCorner; break;
565 }
566 _thirdSectionInfoEnabled = thirdSectionInfoEnabled;
567 _dialogsWidthRatio = dialogsWidthRatio;
568 _thirdColumnWidth = thirdColumnWidth;
569 _thirdSectionExtendedBy = thirdSectionExtendedBy;
570 if (_thirdSectionInfoEnabled) {
571 _tabbedSelectorSectionEnabled = false;
572 }
573 _notifyFromAll = (notifyFromAll == 1);
574 _nativeWindowFrame = (nativeWindowFrame == 1);
575 _systemDarkModeEnabled = (systemDarkModeEnabled == 1);
576 _groupCallPushToTalk = (groupCallPushToTalk == 1);
577 _groupCallPushToTalkShortcut = groupCallPushToTalkShortcut;
578 _groupCallPushToTalkDelay = groupCallPushToTalkDelay;
579 _disableCalls = (disableCalls == 1);
580 if (!windowPosition.isEmpty()) {
581 _windowPosition = Deserialize(windowPosition);
582 }
583 _recentEmojiPreload = std::move(recentEmojiPreload);
584 _emojiVariants = std::move(emojiVariants);
585 _disableOpenGL = (disableOpenGL == 1);
586 if (!Platform::IsMac()) {
587 Ui::GL::ForceDisable(_disableOpenGL
588 || Ui::GL::LastCrashCheckFailed());
589 }
590 _groupCallNoiseSuppression = (groupCallNoiseSuppression == 1);
591 const auto uncheckedWorkMode = static_cast<WorkMode>(workMode);
592 switch (uncheckedWorkMode) {
593 case WorkMode::WindowAndTray:
594 case WorkMode::TrayOnly:
595 case WorkMode::WindowOnly: _workMode = uncheckedWorkMode; break;
596 }
597 _hiddenGroupCallTooltips = [&] {
598 using Tooltip = Calls::Group::StickedTooltip;
599 return Tooltip(0)
600 | ((hiddenGroupCallTooltips & int(Tooltip::Camera))
601 ? Tooltip::Camera
602 : Tooltip(0))
603 | ((hiddenGroupCallTooltips & int(Tooltip::Microphone))
604 ? Tooltip::Microphone
605 : Tooltip(0));
606 }();
607 _photoEditorBrush = photoEditorBrush;
608 _closeToTaskbar = (closeToTaskbar == 1);
609 }
610
getSoundPath(const QString & key) const611 QString Settings::getSoundPath(const QString &key) const {
612 auto it = _soundOverrides.find(key);
613 if (it != _soundOverrides.end()) {
614 return it->second;
615 }
616 return qsl(":/sounds/") + key + qsl(".mp3");
617 }
618
setTabbedSelectorSectionEnabled(bool enabled)619 void Settings::setTabbedSelectorSectionEnabled(bool enabled) {
620 _tabbedSelectorSectionEnabled = enabled;
621 if (enabled) {
622 setThirdSectionInfoEnabled(false);
623 }
624 setTabbedReplacedWithInfo(false);
625 }
626
tabbedReplacedWithInfoValue() const627 rpl::producer<bool> Settings::tabbedReplacedWithInfoValue() const {
628 return _tabbedReplacedWithInfoValue.events_starting_with(
629 tabbedReplacedWithInfo());
630 }
631
setThirdSectionInfoEnabled(bool enabled)632 void Settings::setThirdSectionInfoEnabled(bool enabled) {
633 if (_thirdSectionInfoEnabled != enabled) {
634 _thirdSectionInfoEnabled = enabled;
635 if (enabled) {
636 setTabbedSelectorSectionEnabled(false);
637 }
638 setTabbedReplacedWithInfo(false);
639 _thirdSectionInfoEnabledValue.fire_copy(enabled);
640 }
641 }
642
thirdSectionInfoEnabledValue() const643 rpl::producer<bool> Settings::thirdSectionInfoEnabledValue() const {
644 return _thirdSectionInfoEnabledValue.events_starting_with(
645 thirdSectionInfoEnabled());
646 }
647
setTabbedReplacedWithInfo(bool enabled)648 void Settings::setTabbedReplacedWithInfo(bool enabled) {
649 if (_tabbedReplacedWithInfo != enabled) {
650 _tabbedReplacedWithInfo = enabled;
651 _tabbedReplacedWithInfoValue.fire_copy(enabled);
652 }
653 }
654
callAudioBackend() const655 Webrtc::Backend Settings::callAudioBackend() const {
656 return Webrtc::Backend::OpenAL;
657 }
658
setDialogsWidthRatio(float64 ratio)659 void Settings::setDialogsWidthRatio(float64 ratio) {
660 _dialogsWidthRatio = ratio;
661 }
662
dialogsWidthRatio() const663 float64 Settings::dialogsWidthRatio() const {
664 return _dialogsWidthRatio.current();
665 }
666
dialogsWidthRatioChanges() const667 rpl::producer<float64> Settings::dialogsWidthRatioChanges() const {
668 return _dialogsWidthRatio.changes();
669 }
670
setThirdColumnWidth(int width)671 void Settings::setThirdColumnWidth(int width) {
672 _thirdColumnWidth = width;
673 }
674
thirdColumnWidth() const675 int Settings::thirdColumnWidth() const {
676 return _thirdColumnWidth.current();
677 }
678
thirdColumnWidthChanges() const679 rpl::producer<int> Settings::thirdColumnWidthChanges() const {
680 return _thirdColumnWidth.changes();
681 }
682
recentEmoji() const683 const std::vector<Settings::RecentEmoji> &Settings::recentEmoji() const {
684 if (_recentEmoji.empty()) {
685 resolveRecentEmoji();
686 }
687 return _recentEmoji;
688 }
689
resolveRecentEmoji() const690 void Settings::resolveRecentEmoji() const {
691 const auto haveAlready = [&](EmojiPtr emoji) {
692 return ranges::contains(
693 _recentEmoji,
694 emoji->id(),
695 [](const RecentEmoji &data) { return data.emoji->id(); });
696 };
697 if (!_recentEmojiPreload.empty()) {
698 _recentEmoji.reserve(_recentEmojiPreload.size());
699 for (const auto &[id, rating] : base::take(_recentEmojiPreload)) {
700 if (const auto emoji = Ui::Emoji::Find(id)) {
701 if (!haveAlready(emoji)) {
702 _recentEmoji.push_back({ emoji, rating });
703 }
704 }
705 }
706 _recentEmojiPreload.clear();
707 }
708 for (const auto emoji : Ui::Emoji::GetDefaultRecent()) {
709 if (_recentEmoji.size() >= kRecentEmojiLimit) {
710 break;
711 } else if (!haveAlready(emoji)) {
712 _recentEmoji.push_back({ emoji, 1 });
713 }
714 }
715 }
716
recentEmojiSection() const717 EmojiPack Settings::recentEmojiSection() const {
718 const auto &recent = recentEmoji();
719
720 auto result = EmojiPack();
721 result.reserve(recent.size());
722 for (const auto &[emoji, rating] : recent) {
723 result.push_back(emoji);
724 }
725 return result;
726 }
727
incrementRecentEmoji(EmojiPtr emoji)728 void Settings::incrementRecentEmoji(EmojiPtr emoji) {
729 resolveRecentEmoji();
730
731 auto i = _recentEmoji.begin(), e = _recentEmoji.end();
732 for (; i != e; ++i) {
733 if (i->emoji == emoji) {
734 ++i->rating;
735 if (i->rating > 0x8000) {
736 for (auto j = _recentEmoji.begin(); j != e; ++j) {
737 if (j->rating > 1) {
738 j->rating /= 2;
739 } else {
740 j->rating = 1;
741 }
742 }
743 }
744 for (; i != _recentEmoji.begin(); --i) {
745 if ((i - 1)->rating > i->rating) {
746 break;
747 }
748 std::swap(*i, *(i - 1));
749 }
750 break;
751 }
752 }
753 if (i == e) {
754 while (_recentEmoji.size() >= kRecentEmojiLimit) {
755 _recentEmoji.pop_back();
756 }
757 _recentEmoji.push_back({ emoji, 1 });
758 for (i = _recentEmoji.end() - 1; i != _recentEmoji.begin(); --i) {
759 if ((i - 1)->rating > i->rating) {
760 break;
761 }
762 std::swap(*i, *(i - 1));
763 }
764 }
765 _recentEmojiUpdated.fire({});
766 _saveDelayed.fire({});
767 }
768
setLegacyRecentEmojiPreload(QVector<QPair<QString,ushort>> data)769 void Settings::setLegacyRecentEmojiPreload(
770 QVector<QPair<QString, ushort>> data) {
771 if (!_recentEmojiPreload.empty() || data.isEmpty()) {
772 return;
773 }
774 _recentEmojiPreload.reserve(data.size());
775 for (const auto &[id, rating] : data) {
776 _recentEmojiPreload.push_back({ id, rating });
777 }
778 }
779
saveEmojiVariant(EmojiPtr emoji)780 void Settings::saveEmojiVariant(EmojiPtr emoji) {
781 _emojiVariants[emoji->nonColoredId()] = emoji->variantIndex(emoji);
782 _saveDelayed.fire({});
783 }
784
setLegacyEmojiVariants(QMap<QString,int> data)785 void Settings::setLegacyEmojiVariants(QMap<QString, int> data) {
786 if (!_emojiVariants.empty() || data.isEmpty()) {
787 return;
788 }
789 _emojiVariants.reserve(data.size());
790 for (auto i = data.begin(), e = data.end(); i != e; ++i) {
791 _emojiVariants.emplace(i.key(), i.value());
792 }
793 }
794
resetOnLastLogout()795 void Settings::resetOnLastLogout() {
796 _adaptiveForWide = true;
797 _moderateModeEnabled = false;
798
799 _songVolume = kDefaultVolume;
800 _videoVolume = kDefaultVolume;
801
802 _askDownloadPath = false;
803 _downloadPath = QString();
804 _downloadPathBookmark = QByteArray();
805
806 _nonDefaultVoicePlaybackSpeed = false;
807 _soundNotify = true;
808 _desktopNotify = true;
809 _flashBounceNotify = true;
810 _notifyView = NotifyView::ShowPreview;
811 //_nativeNotifications = std::nullopt;
812 //_notificationsCount = 3;
813 //_notificationsCorner = ScreenCorner::BottomRight;
814 _includeMutedCounter = true;
815 _countUnreadMessages = true;
816 _notifyAboutPinned = true;
817 //_autoLock = 3600;
818
819 //_callOutputDeviceId = u"default"_q;
820 //_callInputDeviceId = u"default"_q;
821 //_callVideoInputDeviceId = u"default"_q;
822 //_callOutputVolume = 100;
823 //_callInputVolume = 100;
824 //_callAudioDuckingEnabled = true;
825
826 _disableCalls = false;
827
828 _groupCallPushToTalk = false;
829 _groupCallPushToTalkShortcut = QByteArray();
830 _groupCallPushToTalkDelay = 20;
831
832 _groupCallNoiseSuppression = false;
833
834 //_themesAccentColors = Window::Theme::AccentColors();
835
836 _lastSeenWarningSeen = false;
837 _sendFilesWay = Ui::SendFilesWay();
838 //_sendSubmitWay = Ui::InputSubmitSettings::Enter;
839 _soundOverrides = {};
840
841 _exeLaunchWarning = true;
842 _ipRevealWarning = true;
843 _loopAnimatedStickers = true;
844 _largeEmoji = true;
845 _replaceEmoji = true;
846 _suggestEmoji = true;
847 _suggestStickersByEmoji = true;
848 _spellcheckerEnabled = true;
849 _videoPlaybackSpeed = 1.;
850 _voicePlaybackSpeed = 1.;
851 //_videoPipGeometry = QByteArray();
852 _dictionariesEnabled = std::vector<int>();
853 _autoDownloadDictionaries = true;
854 _mainMenuAccountsShown = true;
855 _tabbedSelectorSectionEnabled = false; // per-window
856 _floatPlayerColumn = Window::Column::Second; // per-window
857 _floatPlayerCorner = RectPart::TopRight; // per-window
858 _thirdSectionInfoEnabled = true; // per-window
859 _thirdSectionExtendedBy = -1; // per-window
860 _dialogsWidthRatio = DefaultDialogsWidthRatio(); // per-window
861 _thirdColumnWidth = kDefaultThirdColumnWidth; // p-w
862 _notifyFromAll = true;
863 _tabbedReplacedWithInfo = false; // per-window
864 _systemDarkModeEnabled = false;
865 _hiddenGroupCallTooltips = 0;
866
867 _recentEmojiPreload.clear();
868 _recentEmoji.clear();
869 _emojiVariants.clear();
870
871 _workMode = WorkMode::WindowAndTray;
872 }
873
ThirdColumnByDefault()874 bool Settings::ThirdColumnByDefault() {
875 return Platform::IsMacStoreBuild();
876 }
877
DefaultDialogsWidthRatio()878 float64 Settings::DefaultDialogsWidthRatio() {
879 return ThirdColumnByDefault()
880 ? kDefaultBigDialogsWidthRatio
881 : kDefaultDialogsWidthRatio;
882 }
883
884 } // namespace Core
885