From c04a0e42a73bdfa8d944dba79530ffce79c3a3b8 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 5 Apr 2022 00:00:58 +0300 Subject: [PATCH] Added initial ability to configure notification sound. --- Telegram/CMakeLists.txt | 2 + .../Resources/icons/menu/sound_select.png | Bin 0 -> 503 bytes .../Resources/icons/menu/sound_select@2x.png | Bin 0 -> 892 bytes .../Resources/icons/menu/sound_select@3x.png | Bin 0 -> 1187 bytes Telegram/Resources/langs/lang.strings | 11 + Telegram/SourceFiles/boxes/boxes.style | 9 + Telegram/SourceFiles/boxes/ringtones_box.cpp | 233 ++++++++++++++++++ Telegram/SourceFiles/boxes/ringtones_box.h | 16 ++ Telegram/SourceFiles/menu/menu_mute.cpp | 6 + Telegram/SourceFiles/ui/menu_icons.style | 1 + 10 files changed, 278 insertions(+) create mode 100644 Telegram/Resources/icons/menu/sound_select.png create mode 100644 Telegram/Resources/icons/menu/sound_select@2x.png create mode 100644 Telegram/Resources/icons/menu/sound_select@3x.png create mode 100644 Telegram/SourceFiles/boxes/ringtones_box.cpp create mode 100644 Telegram/SourceFiles/boxes/ringtones_box.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index e44fb61bd..4db166fed 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -252,6 +252,8 @@ PRIVATE boxes/phone_banned_box.h boxes/pin_messages_box.cpp boxes/pin_messages_box.h + boxes/ringtones_box.cpp + boxes/ringtones_box.h boxes/self_destruction_box.cpp boxes/self_destruction_box.h boxes/send_files_box.cpp diff --git a/Telegram/Resources/icons/menu/sound_select.png b/Telegram/Resources/icons/menu/sound_select.png new file mode 100644 index 0000000000000000000000000000000000000000..99587321d6986b20c2d277029546838758f62e04 GIT binary patch literal 503 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfEYZ`&F~mYJ zIYENeS)WDXq2IHI4+BF&T8a%N&GYa5`TANs;LeE?EB5W1*WCR0{r&wsDQK}NU3 zhuirJPcj`9Wc&N$Z^ zS&sZAR;{Q2|KSXVdq-JP8$x;m4- zfBSZCXR*40!G&YT*fQ?yt^R)F=FQGaoy$6Ud)F>r{P^YNvi+}L#=Hy%1-hrJpUXO@geCyAPS$n+ literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/menu/sound_select@2x.png b/Telegram/Resources/icons/menu/sound_select@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..387ea17889b33904c34cbe8222fb8dc1385992b0 GIT binary patch literal 892 zcmV-?1B3jDP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NE=1D|BR9Fe^R?SOlK@?AUmZ(9d zf}g8Oja&q}aUr(wFK{U+ZfxPoMc}GvrHfXA|9~G0L&J@NS{n^YrNEC}xp+Z^8?i-6 zpY+aq^SE5^9dL@0_h9bgdd~0s=A7ei=FZH_41K5qQ~|00Re&n+e=8uETKh7Y%}=L+wFe8 zpUuQHw6?Z(c6P=lebm0az18dWj1n+B5D1`d?(XhTHi1Ae8jVV&(&Xd{g`(H%LAp;r z*=&|mCXq-$wpy*m!TBymA(+&al@*al#AlNrQ26ELg~Obkodx9a@sWe`T}(qjf~3#S z&wTb25aASRe5eF%Xp&s`H8eLjr&KB@jm5`d{lRCCj}f4lhSX|xx7+=6Lr@ep#*K{) zg6bFwW)02H&o3@6Vz|VR!C-)WkC;A2#3*!mdAYQ-WHcJbh{O&|S)+35Rl}cq|D;R|&63PDlKL0Ys$puIE z?(Xiv!2!Y@4o4&s0lV3327|%#^K-C;LZQdwiN#`Q9|4z>gvhnoY=8geq@R2~&t%MG zGC;q+zLv}742TSu%Y`y^Ivq}k?_v~!>!Q!+TU}k{v)KqJluRZW#AGsoT`rf0!yyAA z!<*=$yXo@sGM@?ag<3g0Jmg2e3)$M*Lh}*|h1fM< zMHUJL2)(_%Ar;xtZ?r*!lamwFQ@vi_+1c6L+}zvSgOeYD+uPgUSRR{NtJT6Dh|06y zpiMj;|MYQ-twjn#Rrt<}#p2b~)zi}xTw~Jd^!oZb>3GVc3Qz^80#t#2Ux8l+gOL%^ Sk+OOK00006gA`6MbbHUhz{2b4;uw;_ z`Zn^kc4?r<{(GH`-?d#N5>$c?HE;?Gbsp(x?6i02n$nZ9Kt)J-k%Xj#M27^2r`%DN z);(da&@g=uP-DgC)d~4S0_Dp<;U8ZnyRX*y!?Da`LpRsNls59gf@Qo z@L}1qWg9ja1lEUtIk0QnHZxOG)gmJUg9~@==wyX{2@DLJK7INxGpV)Q+}yK5b_Pa< zhc7qWaJcbHb$$JH`Hb}R&BK$F z)A}tW+&|uT^VxUz_>m(mZEaG^Pwh}WxAE{{=edi|>{u-yT~<3fzh1o>T72PawWr#*PoIn|EmyujG;i&skS*#N$}1|8+#)tj?oH{9 z7{w@5I(>xzz!USXb_ zm$!&*VV=^>BS%!Sb|Y`}c2`+y1ONqBW8$3`IpmCQJr`A3rKewNG~N=lxCL zJm_-7rm8PAG*s|cTU*=X$H`Tp+|Qps-@0{cRxfAdq%L51tXuNv=FOQ>!C6_WK2;SL zH$U3B>!fE~WaQ5M`+;69yL9_YX<1pAr@g-+At52*v3J7! z8H(S^|CBlYRaRAPowZ?CS9iDWuOrI>@2E|gG9}^o;vJnW$B!TX^r>ij?<-078{Z4N z#eF%eTs*%xUohr~l~UE$U%!4mzqsquecc91>cBt)W{KEO*{jd(+c#--)7lG05@`*R i32ZYM5!43-=6Z&on#cK4dmame3J6bEKbLh*2~7ZnI}}I& literal 0 HcmV?d00001 diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 7525ac789..9d0ebaf9f 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -897,6 +897,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_mute_menu_duration_unmute" = "Unmute"; "lng_mute_menu_sound_on" = "Enable sound"; "lng_mute_menu_sound_off" = "Disable sound"; +"lng_mute_menu_sound_select" = "Select sound"; "lng_mute_box_title" = "Mute notifications for..."; "lng_mute_duration_hours#one" = "For {count} hour"; @@ -3113,6 +3114,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_telegram_features_url" = "https://t.me/TelegramTips"; +"lng_ringtones_box_title" = "Notification Sound"; +"lng_ringtones_box_cloud_subtitle" = "Telegram tones"; +"lng_ringtones_box_local_subtitle" = "System notes"; +"lng_ringtones_box_upload" = "Upload Sound"; +"lng_ringtones_box_upload_choose" = "Choose ringtone"; +"lng_ringtones_box_upload_button" = "Upload Sound"; +"lng_ringtones_box_default" = "Default"; +"lng_ringtones_box_no_sound" = "No sound"; +"lng_ringtones_box_error" = "Sorry, but your file is too big."; + // Wnd specific "lng_wnd_choose_program_menu" = "Choose Default Program..."; diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 9d368b64a..6ef61c2d8 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -1055,3 +1055,12 @@ requestsRejectButton: RoundButton(defaultLightButton) { } requestAcceptPosition: point(71px, 58px); requestButtonsSkip: 9px; + +ringtonesBoxListHeight: 192; +ringtonesBoxButton: SettingsButton(defaultSettingsButton) { + textFg: lightButtonFg; + textFgOver: lightButtonFgOver; + padding: margins(56px, 10px, 22px, 8px); + iconLeft: 25px; +} +ringtonesBoxSkip: 7px; diff --git a/Telegram/SourceFiles/boxes/ringtones_box.cpp b/Telegram/SourceFiles/boxes/ringtones_box.cpp new file mode 100644 index 000000000..92a4d0a40 --- /dev/null +++ b/Telegram/SourceFiles/boxes/ringtones_box.cpp @@ -0,0 +1,233 @@ +/* +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 "boxes/ringtones_box.h" + +#include "api/api_ringtones.h" +#include "apiwrap.h" +#include "base/base_file_utilities.h" +#include "base/call_delayed.h" +#include "base/event_filter.h" +#include "core/file_utilities.h" +#include "core/mime_type.h" +#include "data/data_document.h" +#include "data/data_peer.h" +#include "data/data_session.h" +#include "data/notify/data_notify_settings.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" +#include "settings/settings_common.h" +#include "ui/boxes/confirm_box.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" +#include "ui/widgets/labels.h" +#include "ui/widgets/popup_menu.h" +#include "ui/widgets/scroll_area.h" +#include "ui/wrap/padding_wrap.h" +#include "ui/wrap/vertical_layout.h" +#include "styles/style_menu_icons.h" +#include "styles/style_boxes.h" +#include "styles/style_layers.h" +#include "styles/style_window.h" + +namespace { + +constexpr auto kDefaultValue = -1; +constexpr auto kNoSoundValue = -2; + +} // namespace + +void RingtonesBox( + not_null box, + not_null peer) { + box->setTitle(tr::lng_ringtones_box_title()); + + const auto container = box->verticalLayout(); + + auto padding = st::boxPadding; + padding.setTop(padding.bottom()); + + struct State { + std::shared_ptr group; + std::vector documentIds; + base::unique_qptr menu; + }; + const auto state = container->lifetime().make_state(State{ + std::make_shared( + peer->owner().notifySettings().sound(peer).none + ? kNoSoundValue + : kDefaultValue), + }); + + const auto addToGroup = [=]( + not_null verticalLayout, + int value, + const QString &text) { + const auto button = verticalLayout->add( + object_ptr( + verticalLayout, + state->group, + value, + text, + st::defaultCheckbox), + padding); + if (value < 0) { + return; + } + base::install_event_filter(button, [=](not_null e) { + if (state->menu || e->type() != QEvent::ContextMenu) { + return base::EventFilterResult::Continue; + } + state->menu = base::make_unique_q( + button, + st::popupMenuWithIcons); + auto callback = [=] { + const auto id = state->documentIds[value]; + peer->session().api().ringtones().remove(id); + }; + state->menu->addAction( + tr::lng_box_delete(tr::now), + std::move(callback), + &st::menuIconDelete); + state->menu->popup(QCursor::pos()); + return base::EventFilterResult::Cancel; + }); + }; + + peer->session().api().ringtones().uploadFails( + ) | rpl::start_with_next([=](const QString &error) { + if ((error == u"RINGTONE_DURATION_TOO_LONG"_q) + || (error == u"RINGTONE_SIZE_TOO_BIG"_q)) { + box->getDelegate()->show( + Ui::MakeInformBox(tr::lng_ringtones_box_error())); + } else if (error == u"RINGTONE_MIME_INVALID"_q) { + box->getDelegate()->show( + Ui::MakeInformBox(tr::lng_edit_media_invalid_file())); + } + }, box->lifetime()); + + Settings::AddSubsectionTitle( + container, + tr::lng_ringtones_box_cloud_subtitle()); + + const auto emptyContent = box->addRow( + object_ptr(container), + style::margins()); + const auto scroll = Ui::CreateChild( + emptyContent, + st::boxScroll); + emptyContent->widthValue( + ) | rpl::start_with_next([=](int width) { + scroll->resize(width, scroll->height()); + }, emptyContent->lifetime()); + scroll->heightValue( + ) | rpl::start_with_next([=](int height) { + emptyContent->resize(emptyContent->width(), height); + }, scroll->lifetime()); + + { + peer->session().api().ringtones().listUpdates( + ) | rpl::start_with_next([=] { + state->documentIds.clear(); + const auto list = scroll->setOwnedWidget( + object_ptr(scroll)); + list->sizeValue( + ) | rpl::start_with_next([=](const QSize &s) { + scroll->resize( + scroll->width(), + std::min(s.height(), st::ringtonesBoxListHeight)); + }, list->lifetime()); + list->resize(scroll->size()); + auto value = 0; + const auto checkedId = peer->owner().notifySettings().sound(peer); + for (const auto &id : peer->session().api().ringtones().list()) { + const auto document = peer->session().data().document(id); + addToGroup(list, value++, document->filename()); + state->documentIds.push_back(id); + if (checkedId.id && checkedId.id == id) { + state->group->setValue(value - 1); + } + } + }, scroll->lifetime()); + + peer->session().api().ringtones().requestList(); + } + + const auto upload = box->addRow( + Settings::CreateButton( + container, + tr::lng_ringtones_box_upload_button(), + st::ringtonesBoxButton, + { + &st::mainMenuAddAccount, + 0, + Settings::IconType::Round, + &st::windowBgActive + }), + style::margins()); + upload->addClickHandler([=] { + const auto delay = st::ringtonesBoxButton.ripple.hideDuration; + base::call_delayed(delay, crl::guard(box, [=] { + const auto callback = [=](const FileDialog::OpenResult &result) { + auto mime = QString(); + auto name = QString(); + auto content = result.remoteContent; + if (!result.paths.isEmpty()) { + auto info = QFileInfo(result.paths.front()); + mime = Core::MimeTypeForFile(info).name(); + name = info.fileName(); + auto f = QFile(result.paths.front()); + if (f.open(QIODevice::ReadOnly)) { + content = f.readAll(); + f.close(); + } + } else { + mime = Core::MimeTypeForData(content).name(); + name = "audio"; + } + + peer->session().api().ringtones().upload(name, mime, content); + }; + FileDialog::GetOpenPath( + box.get(), + tr::lng_ringtones_box_upload_choose(tr::now), + "Audio files (*.mp3)", + crl::guard(box, callback)); + })); + }); + + box->addSkip(st::ringtonesBoxSkip); + Settings::AddDivider(container); + + box->addSkip(st::ringtonesBoxSkip); + + Settings::AddSubsectionTitle( + container, + tr::lng_ringtones_box_local_subtitle()); + + addToGroup(container, kDefaultValue, tr::lng_ringtones_box_default({})); + addToGroup(container, kNoSoundValue, tr::lng_ringtones_box_no_sound({})); + + box->addSkip(st::ringtonesBoxSkip); + + box->setWidth(st::boxWideWidth); + box->addButton(tr::lng_settings_save(), [=] { + const auto value = state->group->value(); + auto sound = (value == kDefaultValue) + ? Data::NotifySound() + : (value == kNoSoundValue) + ? Data::NotifySound{ .none = true } + : Data::NotifySound{ .id = state->documentIds[value] }; + peer->owner().notifySettings().updateNotifySettings( + peer, + std::nullopt, + std::nullopt, + sound); + box->closeBox(); + }); + box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); +} diff --git a/Telegram/SourceFiles/boxes/ringtones_box.h b/Telegram/SourceFiles/boxes/ringtones_box.h new file mode 100644 index 000000000..bea10f50b --- /dev/null +++ b/Telegram/SourceFiles/boxes/ringtones_box.h @@ -0,0 +1,16 @@ +/* +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 +*/ +#pragma once + +#include "ui/layers/generic_box.h" + +class PeerData; + +void RingtonesBox( + not_null box, + not_null peer); diff --git a/Telegram/SourceFiles/menu/menu_mute.cpp b/Telegram/SourceFiles/menu/menu_mute.cpp index 231b353b2..4c9081a1f 100644 --- a/Telegram/SourceFiles/menu/menu_mute.cpp +++ b/Telegram/SourceFiles/menu/menu_mute.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "menu/menu_mute.h" +#include "boxes/ringtones_box.h" #include "data/data_peer.h" #include "data/data_session.h" #include "data/notify/data_notify_settings.h" @@ -230,6 +231,11 @@ void FillMuteMenu( Args args) { const auto peer = args.peer; + menu->addAction( + tr::lng_mute_menu_sound_select(tr::now), + [=, show = args.show] { show->showBox(Box(RingtonesBox, peer)); }, + &st::menuIconSoundSelect); + const auto soundIsNone = peer->owner().notifySettings().sound(peer).none; menu->addAction( soundIsNone diff --git a/Telegram/SourceFiles/ui/menu_icons.style b/Telegram/SourceFiles/ui/menu_icons.style index 261042d5c..dad37e892 100644 --- a/Telegram/SourceFiles/ui/menu_icons.style +++ b/Telegram/SourceFiles/ui/menu_icons.style @@ -107,6 +107,7 @@ menuIconSilent: icon {{ "menu/silent", menuIconColor }}; menuIconCustomize: icon {{ "menu/customize", menuIconColor }}; menuIconSoundOn: icon {{ "menu/sound_enable", menuIconColor }}; menuIconSoundOff: icon {{ "menu/sound_disable", menuIconColor }}; +menuIconSoundSelect: icon {{ "menu/sound_select", menuIconColor }}; menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }}; menuIconTTLAnyTextPosition: point(11px, 22px);