diff --git a/Telegram/SourceFiles/ayu/ui/components/saved_music.cpp b/Telegram/SourceFiles/ayu/ui/components/saved_music.cpp index d5a2f33d08..7d1ae6f772 100644 --- a/Telegram/SourceFiles/ayu/ui/components/saved_music.cpp +++ b/Telegram/SourceFiles/ayu/ui/components/saved_music.cpp @@ -23,6 +23,7 @@ #include "styles/palette.h" #include "styles/style_info.h" #include "ui/painter.h" +#include "ui/ui_utility.h" #include "ui/image/image.h" #include "ui/widgets/labels.h" #include "window/themes/window_theme.h" @@ -54,8 +55,15 @@ QRgb BlendARGB(QRgb color1, QRgb color2, float ratio) { return qRgba(r, g, b, a); } -QColor GetNoCoverBgColor() { - return Window::Theme::IsNightMode() ? st::windowBgOver->c.darker(170) : st::windowBgOver->c; +QColor GetNoCoverBgColor(std::optional overrideBg) { + if (overrideBg) { + return Ui::BlendColors( + *overrideBg, + Qt::black, + st::infoProfileTopBarActionButtonBgOpacity); + } + + return st::shadowFg->c; } struct Cover @@ -171,6 +179,7 @@ std::optional ExtractColorFromCover(const QPixmap &cover) { AyuMusicButton::AyuMusicButton( QWidget *parent, MusicButtonData data, + std::optional overrideBg, Fn handler) : RippleButton(parent, st::infoMusicButtonRipple) , _performer(std::make_unique( @@ -181,7 +190,8 @@ AyuMusicButton::AyuMusicButton( this, data.title, st::infoMusicButtonTitle)) - , _mediaView(data.mediaView) { + , _mediaView(data.mediaView) + , _overrideBg(overrideBg) { _performerText = data.performer; _titleText = data.title; rpl::combine( @@ -216,92 +226,98 @@ void AyuMusicButton::updateData(MusicButtonData data) { void AyuMusicButton::downloadAndMakeCover(FullMsgId msgId) { if (_mediaView && _mediaView->owner()->isSongWithCover() && !_mediaView->thumbnail()) { - const auto settings = &_mediaView->owner()->session().settings().autoDownload(); - // Data::AutoDownload::Type::Music always returns false - if (settings->shouldDownload(Data::AutoDownload::Source::User, Data::AutoDownload::Type::File, _mediaView->owner()->size)) { - _mediaView->thumbnailWanted(Data::FileOrigin(msgId)); - _mediaView->owner()->owner().session().downloaderTaskFinished( - ) | rpl::take_while([=] - { - if (_mediaView->thumbnail()) { - makeCover(); - } - return !_mediaView->thumbnail(); - }) | rpl::start(lifetime()); - return; - } + const auto settings = &_mediaView->owner()->session().settings().autoDownload(); + // Data::AutoDownload::Type::Music always returns false + if (settings->shouldDownload(Data::AutoDownload::Source::User, + Data::AutoDownload::Type::File, + _mediaView->owner()->size)) { + _mediaView->thumbnailWanted(Data::FileOrigin(msgId)); + _mediaView->owner()->owner().session().downloaderTaskFinished( + ) | rpl::take_while([=] + { + if (_mediaView->thumbnail()) { + makeCover(); + } + return !_mediaView->thumbnail(); + }) | rpl::start(lifetime()); + return; + } } - makeCover(); + makeCover(); } void AyuMusicButton::makeCover() { const auto weak = base::make_weak(this); - crl::async([=, mediaView = _mediaView, performerText = _performerText, titleText = _titleText]() - { - const auto &settings = AyuSettings::getInstance(); - const auto &font = st::infoMusicButtonTitle.style.font; - const auto skip = st::normalFont->spacew / 2; - const auto size = font->height + skip + font->height; + crl::async( + [=, mediaView = _mediaView, performerText = _performerText, titleText = _titleText, overrideBg = _overrideBg]() + { + const auto &settings = AyuSettings::getInstance(); + const auto &font = st::infoMusicButtonTitle.style.font; + const auto skip = st::normalFont->spacew / 2; + const auto size = font->height + skip + font->height; - auto cover = GetCurrentCover(mediaView, QSize(size, size)); + auto cover = GetCurrentCover(mediaView, QSize(size, size)); - if (cover.noCover) { - const auto pix = Ayu::Ui::Itunes::FetchCover(performerText, titleText, size); - if (!pix.isNull()) { - const auto img = Image(pix.toImage()); - const auto args = Images::PrepareArgs{ - .options = Images::Option::RoundSmall, - .outer = QSize(size, size), - }; - cover.pixToDraw = img.pix(QSize(size, size), args); - cover.pixToBg = pix; - cover.noCover = false; - } - } - - QColor bgColor; - if (cover.noCover || !settings.adaptiveCoverColor) { - bgColor = GetNoCoverBgColor(); - } else { - if (const auto extractedColor = ExtractColorFromCover(cover.pixToBg)) { - bgColor = QColor::fromRgb(*extractedColor); - } else { // example: fully black image - cover.noCover = true; - bgColor = GetNoCoverBgColor(); - } - } - - crl::on_main([weak, cover = std::move(cover), bgColor]() mutable { - const auto strong = weak.get(); - if (!strong) { - return; + if (cover.noCover) { + const auto pix = Ayu::Ui::Itunes::FetchCover(performerText, titleText, size); + if (!pix.isNull()) { + const auto img = Image(pix.toImage()); + const auto args = Images::PrepareArgs{ + .options = Images::Option::RoundSmall, + .outer = QSize(size, size), + }; + cover.pixToDraw = img.pix(QSize(size, size), args); + cover.pixToBg = pix; + cover.noCover = false; + } } - strong->_currentCover = { - .pix = cover.pixToDraw, - .bg = bgColor, - .noCover = cover.noCover, - }; - - const auto &settings2 = AyuSettings::getInstance(); - const auto &cover2 = *strong->_currentCover; - - if (!cover2.noCover && settings2.adaptiveCoverColor && !cover2.pix.isNull()) { - strong->_title->setTextColorOverride(Qt::white); - strong->_performer->setTextColorOverride(performerColor); + QColor bgColor; + if (cover.noCover || !settings.adaptiveCoverColor) { + bgColor = GetNoCoverBgColor(overrideBg); } else { - strong->_title->setTextColorOverride(std::nullopt); - strong->_performer->setTextColorOverride(std::nullopt); + if (const auto extractedColor = ExtractColorFromCover(cover.pixToBg)) { + bgColor = QColor::fromRgb(*extractedColor); + } else { + // example: fully black image + cover.noCover = true; + bgColor = GetNoCoverBgColor(overrideBg); + } } - strong->repaint(); - strong->_title->repaint(); - strong->_performer->repaint(); + crl::on_main([weak, cover = std::move(cover), bgColor, overrideBg]() mutable + { + const auto strong = weak.get(); + if (!strong) { + return; + } - strong->_onReady.fire({}); + strong->_currentCover = { + .pix = cover.pixToDraw, + .bg = bgColor, + .noCover = cover.noCover, + }; + + const auto &settings2 = AyuSettings::getInstance(); + const auto &cover2 = *strong->_currentCover; + + if (!cover2.noCover && settings2.adaptiveCoverColor && !cover2.pix.isNull()) { + strong->_title->setTextColorOverride(Qt::white); + strong->_performer->setTextColorOverride(performerColor); + } else { + strong->_title->setTextColorOverride(overrideBg ? st::groupCallMembersFg->c : st::windowBoldFg->c); + strong->_performer->setTextColorOverride( + overrideBg ? st::groupCallMembersFg->c : st::windowBoldFg->c); + } + + strong->repaint(); + strong->_title->repaint(); + strong->_performer->repaint(); + + strong->_onReady.fire({}); + }); }); - }); } void AyuMusicButton::paintEvent(QPaintEvent *e) { diff --git a/Telegram/SourceFiles/ayu/ui/components/saved_music.h b/Telegram/SourceFiles/ayu/ui/components/saved_music.h index 62357a078b..a812e96442 100644 --- a/Telegram/SourceFiles/ayu/ui/components/saved_music.h +++ b/Telegram/SourceFiles/ayu/ui/components/saved_music.h @@ -27,9 +27,10 @@ struct ResultCover bool noCover; }; -class AyuMusicButton final : public Ui::RippleButton { +class AyuMusicButton final : public Ui::RippleButton +{ public: - AyuMusicButton(QWidget *parent, MusicButtonData data, Fn handler); + AyuMusicButton(QWidget *parent, MusicButtonData data, std::optional overrideBg, Fn handler); ~AyuMusicButton(); void updateData(MusicButtonData data); @@ -54,6 +55,8 @@ private: QString _performerText; QString _titleText; + std::optional _overrideBg; + }; } // namespace Info::Profile diff --git a/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp b/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp index cfa9a38710..d4803ae12f 100644 --- a/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp +++ b/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp @@ -469,7 +469,7 @@ void BottomInfo::layoutDateText() { const auto prefix = !author.isEmpty() ? u", "_q : QString(); const auto date = edited + ((_data.flags & Data::Flag::ForwardedDate) ? Ui::FormatDateTimeSavedFrom(_data.date, true) - : formatMessageTime(_data.date.time()); + : formatMessageTime(_data.date.time())); const auto afterAuthor = prefix + date; const auto afterAuthorWidth = st::msgDateFont->width(afterAuthor); const auto authorWidth = st::msgDateFont->width(author); diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index a9c7d16ee0..e8c1b617db 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -1448,3 +1448,14 @@ earnTonIconMargin: margins(0px, 2px, 0px, 0px); infoMusicButtonRipple: universalRippleAnimation; infoMusicButtonPadding: margins(12px, 8px, 24px, 8px); +infoMusicButtonPerformer: FlatLabel(defaultFlatLabel) { + textFg: windowSubTextFg; + maxHeight: 20px; +} +infoMusicButtonTitle: FlatLabel(defaultFlatLabel) { + textFg: windowBoldFg; + style: semiboldTextStyle; + maxHeight: 20px; +} +infoMusicButtonBottom: 8px; +infoMusicButtonLine: 2px; diff --git a/Telegram/SourceFiles/info/profile/info_profile_music_button.h b/Telegram/SourceFiles/info/profile/info_profile_music_button.h index 64a22e60af..bf425e63f4 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_music_button.h +++ b/Telegram/SourceFiles/info/profile/info_profile_music_button.h @@ -19,6 +19,8 @@ namespace Info::Profile { struct MusicButtonData { Ui::Text::FormatSongName name; + QString title; + QString performer; FullMsgId msgId; std::shared_ptr mediaView; }; diff --git a/Telegram/SourceFiles/info/saved/info_saved_music_common.cpp b/Telegram/SourceFiles/info/saved/info_saved_music_common.cpp index 53a46281b6..724f76c37d 100644 --- a/Telegram/SourceFiles/info/saved/info_saved_music_common.cpp +++ b/Telegram/SourceFiles/info/saved/info_saved_music_common.cpp @@ -21,13 +21,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/wrap/vertical_layout.h" #include "ui/vertical_list.h" +// AyuGram includes +#include "lang_auto.h" +#include "ayu/ayu_settings.h" +#include "ayu/ui/components/saved_music.h" +#include "ayu/utils/telegram_helpers.h" +#include "data/data_document.h" +#include "styles/style_menu_icons.h" +#include "ui/widgets/popup_menu.h" + namespace Info::Saved { namespace { [[nodiscard]] Profile::MusicButtonData DocumentMusicButtonData( - not_null document) { - return { Ui::Text::FormatSongNameFor(document) }; + not_null document, not_null message) { + const auto name = Ui::Text::FormatSongNameFor(document); + + return { + .name = name, + .title = name.composedName().title, + .performer = name.composedName().performer, + .msgId = message->fullId(), + .mediaView = document->createMediaView(), + }; } } // namespace @@ -65,14 +82,74 @@ void SetupSavedMusic( if (const auto document = item->media() ? item->media()->document() : nullptr) { - const auto music = divider->entity()->add( - object_ptr( + auto musicButton = divider->entity()->add(object_ptr>( + divider->entity(), + object_ptr( divider->entity(), - DocumentMusicButtonData(document), - [window = controller, peer] { + DocumentMusicButtonData(document, item), + color, + [window = controller, peer] + { window->showSection(Info::Saved::MakeMusic(peer)); - })); - music->setOverrideBg(color); + }))); + + musicButton->hide(anim::type::instant); + musicButton->ease = anim::easeOutCubic; + musicButton->setDuration(250); + musicButton->entity()->setAcceptBoth(true); + musicButton->entity()->clicks() | rpl::filter([=](Qt::MouseButton mouseButton) + { + return mouseButton == Qt::RightButton; + }) | rpl::start_with_next([=] + { + const auto &settings = AyuSettings::getInstance(); + + const auto contextMenu = new Ui::PopupMenu( + nullptr, + st::popupMenuWithIcons); + contextMenu->setAttribute(Qt::WA_DeleteOnClose); + + contextMenu->addAction( + settings.adaptiveCoverColor + ? tr::ayu_DisableColorfulCover(tr::now) + : tr::ayu_EnableColorfulCover(tr::now), + [=] + { + AyuSettings::set_adaptiveCoverColor(!settings.adaptiveCoverColor); + AyuSettings::save(); + + const auto mediaRefreshed = item ? item->media() : nullptr; + const auto documentRefreshed = mediaRefreshed + ? mediaRefreshed->document() + : nullptr; + + if (!documentRefreshed) { + return; + } + musicButton->entity()->updateData( + DocumentMusicButtonData(documentRefreshed, item)); + }, + &st::menuIconPalette); + + contextMenu->popup(QCursor::pos()); + }, + musicButton->lifetime()); + + const auto weak = base::make_weak(musicButton); + musicButton->entity()->onReady() | rpl::start_with_next( + [=] + { + // fix animation glitch + dispatchToMainThread( + [=] + { + if (const auto strong = weak.get()) { + strong->show(anim::type::normal); + } + }, + st::widgetFadeDuration); + }, + musicButton->lifetime()); } divider->toggle(true, anim::type::normal); } diff --git a/Telegram/codegen b/Telegram/codegen index 4794244d96..1c919609d4 160000 --- a/Telegram/codegen +++ b/Telegram/codegen @@ -1 +1 @@ -Subproject commit 4794244d96cc6917a84578ce5ac16809fb698e3a +Subproject commit 1c919609d4573f2be91dafef923f8f9e2c08cdff diff --git a/Telegram/lib_icu b/Telegram/lib_icu index 6c828925ef..fd92c31845 160000 --- a/Telegram/lib_icu +++ b/Telegram/lib_icu @@ -1 +1 @@ -Subproject commit 6c828925eff8bc07333138afbd61d9bb177a64e8 +Subproject commit fd92c3184598c4e64c10c1961a3c767d43b10b5c diff --git a/Telegram/lib_ui b/Telegram/lib_ui index b98743aa81..5bc7b6fb5b 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit b98743aa8103c9abbf56f588b52828dece143df6 +Subproject commit 5bc7b6fb5ba36a2735ae4d158cdfa81f04782f19