diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index dc6c1a0ca..2fca05c05 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -633,6 +633,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_section_devices" = "Speakers and Camera"; "lng_settings_devices_calls" = "Calls and video chats"; "lng_settings_devices_calls_same" = "Use the same devices for calls"; +"lng_settings_devices_inactive" = "Unavailable"; "lng_settings_language" = "Language"; "lng_settings_default_scale" = "Default interface scale"; diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp index 0db565716..29f6fa393 100644 --- a/Telegram/SourceFiles/core/core_settings.cpp +++ b/Telegram/SourceFiles/core/core_settings.cpp @@ -160,8 +160,8 @@ QByteArray Settings::serialize() const { + Serialize::stringSize(_downloadPath.current()) + Serialize::bytearraySize(_downloadPathBookmark) + sizeof(qint32) * 9 - + Serialize::stringSize(_callPlaybackDeviceId.current()) - + Serialize::stringSize(_callCaptureDeviceId.current()) + + Serialize::stringSize(QString()) // legacy call output device id + + Serialize::stringSize(QString()) // legacy call input device id + sizeof(qint32) * 5; for (const auto &[key, value] : _soundOverrides) { size += Serialize::stringSize(key) + Serialize::stringSize(value); @@ -207,7 +207,9 @@ QByteArray Settings::serialize() const { } size += sizeof(qint32) * 2 + Serialize::stringSize(_playbackDeviceId.current()) - + Serialize::stringSize(_captureDeviceId.current()); + + Serialize::stringSize(_captureDeviceId.current()) + + Serialize::stringSize(_callPlaybackDeviceId.current()) + + Serialize::stringSize(_callCaptureDeviceId.current()); auto result = QByteArray(); result.reserve(size); @@ -232,8 +234,8 @@ QByteArray Settings::serialize() const { << qint32(_notificationsCount) << static_cast(_notificationsCorner) << qint32(_autoLock) - << _callPlaybackDeviceId.current() - << _callCaptureDeviceId.current() + << QString() // legacy call output device id + << QString() // legacy call input device id << qint32(_callOutputVolume) << qint32(_callInputVolume) << qint32(_callAudioDuckingEnabled ? 1 : 0) @@ -349,7 +351,9 @@ QByteArray Settings::serialize() const { << qint32(_trayIconMonochrome.current() ? 1 : 0) << qint32(_ttlVoiceClickTooltipHidden.current() ? 1 : 0) << _playbackDeviceId.current() - << _captureDeviceId.current(); + << _captureDeviceId.current() + << _callPlaybackDeviceId.current() + << _callCaptureDeviceId.current(); } Ensures(result.size() == size); @@ -384,6 +388,8 @@ void Settings::addFromSerialized(const QByteArray &serialized) { QString playbackDeviceId = _playbackDeviceId.current(); QString captureDeviceId = _captureDeviceId.current(); QString cameraDeviceId = _cameraDeviceId.current(); + QString legacyCallPlaybackDeviceId = _callPlaybackDeviceId.current(); + QString legacyCallCaptureDeviceId = _callCaptureDeviceId.current(); QString callPlaybackDeviceId = _callPlaybackDeviceId.current(); QString callCaptureDeviceId = _callCaptureDeviceId.current(); qint32 callOutputVolume = _callOutputVolume; @@ -483,8 +489,8 @@ void Settings::addFromSerialized(const QByteArray &serialized) { >> notificationsCount >> notificationsCorner >> autoLock - >> callPlaybackDeviceId - >> callCaptureDeviceId + >> legacyCallPlaybackDeviceId + >> legacyCallCaptureDeviceId >> callOutputVolume >> callInputVolume >> callAudioDuckingEnabled @@ -728,6 +734,19 @@ void Settings::addFromSerialized(const QByteArray &serialized) { >> playbackDeviceId >> captureDeviceId; } + if (!stream.atEnd()) { + stream + >> callPlaybackDeviceId + >> callCaptureDeviceId; + } else { + const auto &defaultId = Webrtc::kDefaultDeviceId; + callPlaybackDeviceId = (legacyCallPlaybackDeviceId == defaultId) + ? QString() + : legacyCallPlaybackDeviceId; + callCaptureDeviceId = (legacyCallCaptureDeviceId == defaultId) + ? QString() + : legacyCallCaptureDeviceId; + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " "Bad data for Core::Settings::constructFromSerialized()")); diff --git a/Telegram/SourceFiles/settings/settings_calls.cpp b/Telegram/SourceFiles/settings/settings_calls.cpp index c1e8f5989..35b040f3e 100644 --- a/Telegram/SourceFiles/settings/settings_calls.cpp +++ b/Telegram/SourceFiles/settings/settings_calls.cpp @@ -513,6 +513,30 @@ void ChooseAudioDeviceBox( *st, *radioSt), margins); + const auto showUnavailable = [=](QString text) { + AddSkip(other); + AddSubsectionTitle(other, tr::lng_settings_devices_inactive()); + const auto &radio = *radioSt; + const auto button = other->add( + object_ptr(other, fake, 0, text, *st, radio), + margins); + button->show(); + + button->setDisabled(true); + button->finishAnimating(); + button->setAttribute(Qt::WA_TransparentForMouseEvents); + while (other->count() > 3) { + delete other->widgetAt(0); + } + if (const auto width = box->width()) { + other->resizeToWidth(width); + } + }; + const auto hideUnavailable = [=] { + while (other->count() > 0) { + delete other->widgetAt(0); + } + }; const auto selectCurrent = [=](QString current) { state->ignoreValueChange = true; @@ -521,7 +545,7 @@ void ChooseAudioDeviceBox( }); if (current.isEmpty() || current == kDefaultDeviceId) { group->setValue(0); - other->clear(); + hideUnavailable(); } else { auto found = false; for (const auto &[index, id] : state->ids) { @@ -532,7 +556,7 @@ void ChooseAudioDeviceBox( } } if (found) { - other->clear(); + hideUnavailable(); } else { group->setValue(0); const auto i = ranges::find( @@ -540,32 +564,22 @@ void ChooseAudioDeviceBox( current, &DeviceInfo::id); if (i != end(state->list)) { - const auto button = other->add( - object_ptr( - other, - fake, - 0, - i->name, - *st, - *radioSt), - margins); - button->show(); - button->setDisabled(true); - button->finishAnimating(); - button->setAttribute(Qt::WA_TransparentForMouseEvents); - while (other->count() > 1) { - delete other->widgetAt(1); - } - if (const auto width = box->width()) { - other->resizeToWidth(width); - } + showUnavailable(i->name); } else { - other->clear(); + hideUnavailable(); } } } }; + const auto choose = [=](const QString &id) { + const auto weak = Ui::MakeWeak(box); + chosen(id); + if (weak) { + box->closeBox(); + } + }; + std::move( devicesValue ) | rpl::start_with_next([=](std::vector &&list) { @@ -581,9 +595,10 @@ void ChooseAudioDeviceBox( const auto current = state->currentId.current(); for (const auto &info : state->list) { + const auto id = info.id; if (info.inactive) { continue; - } else if (current == info.id) { + } else if (current == id) { group->setValue(index); } const auto button = buttons->insert( @@ -598,8 +613,14 @@ void ChooseAudioDeviceBox( margins); button->show(); button->finishAnimating(); + button->clicks( + ) | rpl::filter([=] { + return (current == id); + }) | rpl::start_with_next([=] { + choose(id); + }, button->lifetime()); - state->ids.emplace(index, info.id); + state->ids.emplace(index, id); if (index < count) { delete buttons->widgetAt(index + 1); } @@ -624,12 +645,8 @@ void ChooseAudioDeviceBox( if (state->ignoreValueChange) { return; } - const auto weak = Ui::MakeWeak(box); const auto i = state->ids.find(value); - chosen((i != end(state->ids)) ? i->second : kDefaultDeviceId); - if (weak) { - box->closeBox(); - } + choose((i != end(state->ids)) ? i->second : kDefaultDeviceId); }); }