From d8ee50c6fe1d76c4f7753eb1ece6214bae570612 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 28 Mar 2022 14:22:11 +0300 Subject: [PATCH] Added ability to set custom mute time. --- Telegram/Resources/icons/menu/mute_for.png | Bin 0 -> 728 bytes Telegram/Resources/icons/menu/mute_for@2x.png | Bin 0 -> 1302 bytes Telegram/Resources/icons/menu/mute_for@3x.png | Bin 0 -> 1900 bytes Telegram/Resources/langs/lang.strings | 6 + Telegram/SourceFiles/boxes/boxes.style | 10 ++ .../info/profile/info_profile_actions.cpp | 2 +- Telegram/SourceFiles/menu/menu_mute.cpp | 168 +++++++++++++++++- Telegram/SourceFiles/menu/menu_mute.h | 10 +- Telegram/SourceFiles/ui/menu_icons.style | 1 + 9 files changed, 191 insertions(+), 6 deletions(-) create mode 100644 Telegram/Resources/icons/menu/mute_for.png create mode 100644 Telegram/Resources/icons/menu/mute_for@2x.png create mode 100644 Telegram/Resources/icons/menu/mute_for@3x.png diff --git a/Telegram/Resources/icons/menu/mute_for.png b/Telegram/Resources/icons/menu/mute_for.png new file mode 100644 index 0000000000000000000000000000000000000000..bd3c183407ee29c68dd2349928840658bdad570f GIT binary patch literal 728 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfyv3!#WBP} z@N9^0_sT?xd4~;VeVSNf;<0h#1_f^Ir9PdTW+)v!bm|hD{ek0Nb&Z=BOzCY^lAd+c zASE%;u-j6*b;6Y^5dx1at|xxl_gSKN+2&c*A4}?EzJIm*e*AM>OpW=^kMiQX_UzfS zcW>(Eo4fC>yP30Z-@dxeBTtJ~Ud^%!SsGNj`|iaImPHjde*AN!wei9-wg~!GO(8bc&vd(?k-jk^#YnRG zU_;!UJ9jGf#$5?oeRbWsbrCw(O03>~ty&p!>hVW`ol{l@Xk4)0f8T%Sw^1NKMg)Kyh6^__pNJ=IG?to!K0f(8yNC!?7?35}jYhBJLC z!dHu)JH9u;#BcfKw`KB^1g&COTkajJWSBe8X`#XN)2c$9ReS5CmRA3BoZ`2fy_vDB zf8OVXenOotilw{Yj3tgTU6Q`fCu&#!3pjHB**#>O2Lytm(8OWT~d)KZ3T z8>jk(&p%}*HwpKy57Cm4nfCdFlU9VWjeMtz6WhJp7c;(yxZU;8oBsWG?fmoY>fh`p zZZWu-wDCrUNz*|E$>v_M2hSV6{}grXZFFcj=X94NuIANYw@bo&zlwIwIh(fp-)1?T zi|hBk`1)(}g4ze~>ca&Uy$GTk!y9=C4&S|s`7O8b6Mw< G&;$S}{6KmD literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/menu/mute_for@2x.png b/Telegram/Resources/icons/menu/mute_for@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..69daac8080fb150ec382422199260e693bf379e7 GIT binary patch literal 1302 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 m8sJ6*j0hMJFe31OiNN1g6IfFF4aN%q0000 DetailsFiller::setupMuteToggle() { MuteMenu::SetupMuteMenu( result.data(), result->clicks() | rpl::to_empty, - peer); + { peer, std::make_shared(_controller) }); object_ptr( result, st::infoIconNotifications, diff --git a/Telegram/SourceFiles/menu/menu_mute.cpp b/Telegram/SourceFiles/menu/menu_mute.cpp index 2dd39e9c75..480ed4b8f8 100644 --- a/Telegram/SourceFiles/menu/menu_mute.cpp +++ b/Telegram/SourceFiles/menu/menu_mute.cpp @@ -7,15 +7,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "menu/menu_mute.h" +#include "base/qt_signal_producer.h" #include "data/data_peer.h" #include "data/data_session.h" #include "info/profile/info_profile_values.h" #include "lang/lang_keys.h" #include "menu/menu_check_item.h" #include "ui/effects/animation_value.h" +#include "ui/layers/generic_box.h" #include "ui/widgets/checkbox.h" +#include "ui/widgets/fields/time_part_input_with_placeholder.h" #include "ui/widgets/menu/menu_action.h" #include "ui/widgets/popup_menu.h" +#include "styles/style_boxes.h" +#include "styles/style_info.h" // infoTopBarMenu +#include "styles/style_layers.h" #include "styles/style_menu_icons.h" namespace MuteMenu { @@ -132,11 +138,162 @@ void FillSoundMenu( }, menu->lifetime()); } +void MuteBox(not_null box, not_null peer) { + using TimeField = Ui::TimePartWithPlaceholder; + const auto putNext = [](not_null field, QChar ch) { + field->setCursorPosition(0); + if (ch.unicode()) { + field->setText(ch + field->getLastText()); + field->setCursorPosition(1); + } + field->onTextEdited(); + field->setFocus(); + }; + + const auto erasePrevious = [](not_null field) { + const auto text = field->getLastText(); + if (!text.isEmpty()) { + field->setCursorPosition(text.size() - 1); + field->setText(text.mid(0, text.size() - 1)); + } + field->setFocus(); + }; + + struct State { + not_null day; + not_null hour; + not_null minute; + + base::unique_qptr menu; + + rpl::variable noSoundChanges; + int valueInSeconds = 0; + }; + + const auto content = box->addRow( + object_ptr(box, st::scheduleHeight)); + + const auto state = box->lifetime().make_state(State{ + .day = Ui::CreateChild( + content, + st::muteBoxTimeField, + rpl::never(), + QString::number(0)), + .hour = Ui::CreateChild( + content, + st::muteBoxTimeField, + rpl::never(), + QString::number(0)), + .minute = Ui::CreateChild( + content, + st::muteBoxTimeField, + rpl::never(), + QString::number(0)), + .noSoundChanges = false, + }); + + const auto day = Ui::MakeWeak(state->day); + const auto hour = Ui::MakeWeak(state->hour); + const auto minute = Ui::MakeWeak(state->minute); + + day->setPhrase(tr::lng_mute_box_days); + day->setMaxValue(31); + day->setWheelStep(1); + day->putNext() | rpl::start_with_next([=](QChar ch) { + putNext(hour, ch); + }, box->lifetime()); + + hour->setPhrase(tr::lng_mute_box_hours); + hour->setMaxValue(23); + hour->setWheelStep(1); + hour->putNext() | rpl::start_with_next([=](QChar ch) { + putNext(minute, ch); + }, box->lifetime()); + hour->erasePrevious() | rpl::start_with_next([=] { + erasePrevious(day); + }, box->lifetime()); + + minute->setPhrase(tr::lng_mute_box_minutes); + minute->setMaxValue(59); + minute->setWheelStep(10); + minute->erasePrevious() | rpl::start_with_next([=] { + erasePrevious(hour); + }, box->lifetime()); + + content->sizeValue( + ) | rpl::start_with_next([=](const QSize &s) { + const auto inputWidth = s.width() / 3; + auto rect = QRect( + 0, + (s.height() - day->height()) / 2, + inputWidth, + day->height()); + for (const auto &input : { day, hour, minute }) { + input->setGeometry(rect - st::muteBoxTimeFieldPadding); + rect.translate(inputWidth, 0); + } + }, box->lifetime()); + + box->setTitle(tr::lng_mute_box_title()); + + const auto topButton = box->addTopButton(st::infoTopBarMenu); + topButton->setClickedCallback([=] { + if (state->menu) { + return; + } + state->menu = base::make_unique_q( + topButton, + st::popupMenuWithIcons); + FillSoundMenu( + state->menu.get(), + peer, + tr::lng_mute_box_no_notifications(), + tr::lng_mute_box_silent_notifications(), + [=](bool silent) { + state->noSoundChanges = silent; + }); + state->menu->popup(QCursor::pos()); + return; + }); + + const auto updateValueInSeconds = [=] { + state->valueInSeconds = 0 + + day->getLastText().toUInt() * 3600 * 24 + + hour->getLastText().toUInt() * 3600 + + minute->getLastText().toUInt() * 60; + }; + + using Field = Ui::MaskedInputField; + auto confirmText = rpl::merge( + base::qt_signal_producer(day.data(), &Field::changed), + base::qt_signal_producer(hour.data(), &Field::changed), + base::qt_signal_producer(minute.data(), &Field::changed), + state->noSoundChanges.value() | rpl::to_empty + ) | rpl::map([=] { + updateValueInSeconds(); + return !state->valueInSeconds + ? tr::lng_mute_menu_unmute() + : state->noSoundChanges.current() + ? tr::lng_mute_box_silent_notifications() + : tr::lng_mute_menu_mute(); + }) | rpl::flatten_latest(); + const auto confirm = box->addButton(std::move(confirmText), [=] { + peer->owner().updateNotifySettings( + peer, + state->valueInSeconds, + std::nullopt, + state->noSoundChanges.current()); + box->closeBox(); + }); + box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); +} + } // namespace void FillMuteMenu( not_null menu, - not_null peer) { + Args args) { + const auto peer = args.peer; FillSoundMenu( menu, @@ -149,6 +306,11 @@ void FillMuteMenu( menu->addSeparator(); + menu->addAction( + tr::lng_mute_menu_duration(tr::now), + [=, show = args.show] { show->showBox(Box(MuteBox, peer)); }, + &st::menuIconMuteFor); + menu->addAction( base::make_unique_q(menu, menu->st().menu, peer)); } @@ -156,7 +318,7 @@ void FillMuteMenu( void SetupMuteMenu( not_null parent, rpl::producer<> triggers, - not_null peer) { + Args args) { struct State { base::unique_qptr menu; }; @@ -170,7 +332,7 @@ void SetupMuteMenu( state->menu = base::make_unique_q( parent, st::popupMenuWithIcons); - FillMuteMenu(state->menu.get(), peer); + FillMuteMenu(state->menu.get(), args); state->menu->popup(QCursor::pos()); }, parent->lifetime()); } diff --git a/Telegram/SourceFiles/menu/menu_mute.h b/Telegram/SourceFiles/menu/menu_mute.h index e0442e3960..a89ea64d61 100644 --- a/Telegram/SourceFiles/menu/menu_mute.h +++ b/Telegram/SourceFiles/menu/menu_mute.h @@ -12,17 +12,23 @@ class PeerData; namespace Ui { class PopupMenu; class RpWidget; +class Show; } // namespace Ui namespace MuteMenu { +struct Args { + not_null peer; + std::shared_ptr show; +}; + void FillMuteMenu( not_null menu, - not_null peer); + Args args); void SetupMuteMenu( not_null parent, rpl::producer<> triggers, - not_null peer); + Args args); } // namespace MuteMenu diff --git a/Telegram/SourceFiles/ui/menu_icons.style b/Telegram/SourceFiles/ui/menu_icons.style index db16b99e71..b3294d0a85 100644 --- a/Telegram/SourceFiles/ui/menu_icons.style +++ b/Telegram/SourceFiles/ui/menu_icons.style @@ -93,6 +93,7 @@ menuIconFake: icon {{ "menu/fake", menuIconColor }}; menuIconPersonal: icon {{ "menu/personal", menuIconColor }}; menuIconPorn: icon {{ "menu/porn", menuIconColor }}; menuIconViolence: icon {{ "menu/violence", menuIconColor }}; +menuIconMuteFor: icon {{ "menu/mute_for", menuIconColor }}; menuIconSilent: icon {{ "menu/silent", menuIconColor }}; mediaMenuIconStickers: icon {{ "menu/stickers", mediaviewMenuFg }};