From 4273167aa2f357f7bb4ba991f659c69a9cfa193c Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 6 Sep 2021 22:45:38 +0300 Subject: [PATCH] Adjust outgoing bubble text and icon colors. --- .../SourceFiles/data/data_cloud_themes.cpp | 2 - .../SourceFiles/history/history_widget.cpp | 32 +++------ Telegram/SourceFiles/history/history_widget.h | 6 -- .../view/history_view_pinned_section.cpp | 15 +++- .../view/history_view_replies_section.cpp | 15 +++- .../view/history_view_scheduled_section.cpp | 15 +++- Telegram/SourceFiles/ui/chat/chat_style.cpp | 13 ++++ Telegram/SourceFiles/ui/chat/chat_style.h | 19 +++++ Telegram/SourceFiles/ui/chat/chat_theme.cpp | 72 ++++++++++++++++++- Telegram/SourceFiles/ui/chat/chat_theme.h | 1 + .../window/window_session_controller.cpp | 1 + 11 files changed, 155 insertions(+), 36 deletions(-) diff --git a/Telegram/SourceFiles/data/data_cloud_themes.cpp b/Telegram/SourceFiles/data/data_cloud_themes.cpp index 0bbda52db..d469a3382 100644 --- a/Telegram/SourceFiles/data/data_cloud_themes.cpp +++ b/Telegram/SourceFiles/data/data_cloud_themes.cpp @@ -421,8 +421,6 @@ void CloudThemes::parseChatThemes(const QVector &list) { .light = CloudTheme::Parse(_session, data.vtheme(), true), .dark = CloudTheme::Parse(_session, data.vdark_theme(), true), }); - AssertIsDebug(); - std::swap(_chatThemes.back().light, _chatThemes.back().dark); }); } } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index d72270cfb..78293d0a8 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -180,11 +180,6 @@ const auto kPsaAboutPrefix = "cloud_lng_about_psa_"; } // namespace -struct HistoryWidget::CustomStyles { - style::TwoIconButton historyToDown; - style::TwoIconButton historyUnreadMentions; -}; - HistoryWidget::HistoryWidget( QWidget *parent, not_null controller) @@ -192,17 +187,23 @@ HistoryWidget::HistoryWidget( parent, controller, ActivePeerValue(controller)) -, _styles(MakeCustomStyles(controller)) , _api(&controller->session().mtp()) , _updateEditTimeLeftDisplay([=] { updateField(); }) , _fieldBarCancel(this, st::historyReplyCancel) , _previewTimer([=] { requestPreview(); }) , _previewState(Data::PreviewState::Allowed) , _topBar(this, controller) -, _scroll(this, st::historyScroll, false) +, _scroll( + this, + controller->chatStyle()->value(lifetime(), st::historyScroll), + false) , _updateHistoryItems([=] { updateHistoryItemsByTimer(); }) -, _historyDown(_scroll, _styles->historyToDown) -, _unreadMentions(_scroll, _styles->historyUnreadMentions) +, _historyDown( + _scroll, + controller->chatStyle()->value(lifetime(), st::historyToDown)) +, _unreadMentions( + _scroll, + controller->chatStyle()->value(lifetime(), st::historyUnreadMentions)) , _fieldAutocomplete(this, controller) , _supportAutocomplete(session().supportMode() ? object_ptr(this, &session()) @@ -323,7 +324,7 @@ HistoryWidget::HistoryWidget( _scroll->hide(); _kbScroll->hide(); - style::PaletteChanged( + controller->chatStyle()->paletteChanged( ) | rpl::start_with_next([=] { _scroll->updateBars(); }, lifetime()); @@ -3991,17 +3992,6 @@ bool HistoryWidget::kbWasHidden() const { return _history && (_keyboard->forMsgId() == FullMsgId(_history->channelId(), _history->lastKeyboardHiddenId)); } -auto HistoryWidget::MakeCustomStyles( - not_null controller) --> std::unique_ptr { - const auto st = controller->chatStyle(); - - auto result = std::make_unique(); - result->historyToDown = st->value(st::historyToDown); - result->historyUnreadMentions = st->value(st::historyUnreadMentions); - return result; -} - void HistoryWidget::toggleKeyboard(bool manual) { auto fieldEnabled = canWriteMessage() && !_a_show.animating(); if (_kbShown || _kbReplyTo) { diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 79db094be..dd69a77fa 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -300,7 +300,6 @@ protected: private: using TabbedPanel = ChatHelpers::TabbedPanel; using TabbedSelector = ChatHelpers::TabbedSelector; - struct CustomStyles; enum ScrollChangeType { ScrollChangeNone, @@ -604,11 +603,6 @@ private: bool kbWasHidden() const; - [[nodiscard]] static std::unique_ptr MakeCustomStyles( - not_null controller); - - const std::unique_ptr _styles; - MTP::Sender _api; MsgId _replyToId = 0; Ui::Text::String _replyToName; diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index 62eb30812..41a0481f0 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/shadow.h" #include "ui/layers/generic_box.h" #include "ui/item_text_options.h" +#include "ui/chat/chat_style.h" #include "ui/toast/toast.h" #include "ui/text/format_values.h" #include "ui/text/text_utilities.h" @@ -95,12 +96,22 @@ PinnedWidget::PinnedWidget( , _migratedPeer(_history->peer->migrateFrom()) , _topBar(this, controller) , _topBarShadow(this) -, _scroll(std::make_unique(this, st::historyScroll, false)) +, _scroll(std::make_unique( + this, + controller->chatStyle()->value(lifetime(), st::historyScroll), + false)) , _clearButton(std::make_unique( this, QString(), st::historyComposeButton)) -, _scrollDown(_scroll.get(), st::historyToDown) { +, _scrollDown( + _scroll.get(), + controller->chatStyle()->value(lifetime(), st::historyToDown)) { + controller->chatStyle()->paletteChanged( + ) | rpl::start_with_next([=] { + _scroll->updateBars(); + }, _scroll->lifetime()); + Window::ChatThemeValueFromPeer( controller, history->peer diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 10478a9e8..32fd90008 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "chat_helpers/send_context_menu.h" // SendMenu::Type. #include "ui/chat/pinned_bar.h" +#include "ui/chat/chat_style.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" #include "ui/wrap/slide_wrap.h" @@ -162,9 +163,19 @@ RepliesWidget::RepliesWidget( controller, ComposeControls::Mode::Normal, SendMenu::Type::SilentOnly)) -, _scroll(std::make_unique(this, st::historyScroll, false)) -, _scrollDown(_scroll.get(), st::historyToDown) +, _scroll(std::make_unique( + this, + controller->chatStyle()->value(lifetime(), st::historyScroll), + false)) +, _scrollDown( + _scroll.get(), + controller->chatStyle()->value(lifetime(), st::historyToDown)) , _readRequestTimer([=] { sendReadTillRequest(); }) { + controller->chatStyle()->paletteChanged( + ) | rpl::start_with_next([=] { + _scroll->updateBars(); + }, _scroll->lifetime()); + Window::ChatThemeValueFromPeer( controller, history->peer diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index c37f757b1..5ef556756 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/layers/generic_box.h" #include "ui/item_text_options.h" #include "ui/toast/toast.h" +#include "ui/chat/chat_style.h" #include "ui/chat/attach/attach_prepare.h" #include "ui/chat/attach/attach_send_files_way.h" #include "ui/special_buttons.h" @@ -91,7 +92,10 @@ ScheduledWidget::ScheduledWidget( not_null history) : Window::SectionWidget(parent, controller, history->peer) , _history(history) -, _scroll(this, st::historyScroll, false) +, _scroll( + this, + controller->chatStyle()->value(lifetime(), st::historyScroll), + false) , _topBar(this, controller) , _topBarShadow(this) , _composeControls(std::make_unique( @@ -99,7 +103,14 @@ ScheduledWidget::ScheduledWidget( controller, ComposeControls::Mode::Scheduled, SendMenu::Type::Disabled)) -, _scrollDown(_scroll, st::historyToDown) { +, _scrollDown( + _scroll, + controller->chatStyle()->value(lifetime(), st::historyToDown)) { + controller->chatStyle()->paletteChanged( + ) | rpl::start_with_next([=] { + _scroll->updateBars(); + }, _scroll->lifetime()); + Window::ChatThemeValueFromPeer( controller, history->peer diff --git a/Telegram/SourceFiles/ui/chat/chat_style.cpp b/Telegram/SourceFiles/ui/chat/chat_style.cpp index c8b68f8b9..e361a5efb 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_style.cpp @@ -472,6 +472,8 @@ void ChatStyle::assignPalette(not_null palette) { _msgBotKbOverBgAddCorners = {}; _msgSelectOverlayCornersSmall = {}; _msgSelectOverlayCornersLarge = {}; + + _paletteChanged.fire({}); } const CornersPixmaps &ChatStyle::serviceBgCornersNormal() const { @@ -616,6 +618,17 @@ void ChatStyle::make( make(my.ripple.color, original.ripple.color); } +void ChatStyle::make( + style::ScrollArea &my, + const style::ScrollArea &original) const { + my = original; + make(my.bg, original.bg); + make(my.bgOver, original.bgOver); + make(my.barBg, original.barBg); + make(my.barBgOver, original.barBgOver); + make(my.shColor, original.shColor); +} + template void ChatStyle::make( Type MessageStyle::*my, diff --git a/Telegram/SourceFiles/ui/chat/chat_style.h b/Telegram/SourceFiles/ui/chat/chat_style.h index 513e55bb8..8215b881a 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.h +++ b/Telegram/SourceFiles/ui/chat/chat_style.h @@ -15,6 +15,7 @@ enum class ImageRoundRadius; namespace style { struct TwoIconButton; +struct ScrollArea; } // namespace style namespace Ui { @@ -138,6 +139,10 @@ public: void apply(not_null theme); + [[nodiscard]] rpl::producer<> paletteChanged() const { + return _paletteChanged.events(); + } + template [[nodiscard]] Type value(const Type &original) const { auto my = Type(); @@ -145,6 +150,15 @@ public: return my; } + template + [[nodiscard]] const Type &value( + rpl::lifetime &parentLifetime, + const Type &original) const { + const auto my = parentLifetime.make_state(); + make(*my, original); + return *my; + } + [[nodiscard]] const CornersPixmaps &serviceBgCornersNormal() const; [[nodiscard]] const CornersPixmaps &serviceBgCornersInverted() const; @@ -241,6 +255,9 @@ private: void make( style::TwoIconButton &my, const style::TwoIconButton &original) const; + void make( + style::ScrollArea &my, + const style::ScrollArea &original) const; [[nodiscard]] MessageStyle &messageStyleRaw( bool outbg, @@ -303,6 +320,8 @@ private: style::icon _historyPollChoiceRight = { Qt::Uninitialized }; style::icon _historyPollChoiceWrong = { Qt::Uninitialized }; + rpl::event_stream<> _paletteChanged; + rpl::lifetime _defaultPaletteChangeLifetime; }; diff --git a/Telegram/SourceFiles/ui/chat/chat_theme.cpp b/Telegram/SourceFiles/ui/chat/chat_theme.cpp index 0a4a73703..a03af571a 100644 --- a/Telegram/SourceFiles/ui/chat/chat_theme.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_theme.cpp @@ -25,6 +25,8 @@ constexpr auto kCacheBackgroundFastTimeout = crl::time(200); constexpr auto kBackgroundFadeDuration = crl::time(200); constexpr auto kMinimumTiledSize = 512; constexpr auto kMaxSize = 2960; +constexpr auto kMaxContrastValue = 21.; +constexpr auto kMinAcceptableContrast = 1.14;// 4.5; [[nodiscard]] QColor DefaultBackgroundColor() { return QColor(213, 223, 233); @@ -133,6 +135,25 @@ constexpr auto kMaxSize = 2960; return Images::GenerateLinearGradient(QSize(kSize, kSize), data.colors); } +// https://stackoverflow.com/a/9733420 +[[nodiscard]] float64 CountContrast(const QColor &a, const QColor &b) { + const auto luminance = [](const QColor &c) { + const auto map = [](double value) { + return (value <= 0.03928) + ? (value / 12.92) + : std::pow((value + 0.055) / 1.055, 2.4); + }; + return map(c.redF()) * 0.2126 + + map(c.greenF()) * 0.7152 + + map(c.blueF()) * 0.0722; + }; + const auto luminance1 = luminance(a); + const auto luminance2 = luminance(b); + const auto brightest = std::max(luminance1, luminance2); + const auto darkest = std::min(luminance1, luminance2); + return (brightest + 0.05) / (darkest + 0.05); +} + } // namespace bool operator==(const ChatThemeBackground &a, const ChatThemeBackground &b) { @@ -201,7 +222,7 @@ void ChatTheme::adjustPalette(const ChatThemeDescriptor &descriptor) { } const auto bubblesAccent = descriptor.bubblesData.accent ? descriptor.bubblesData.accent - : !descriptor.bubblesData.colors.empty() + : (!descriptor.bubblesData.colors.empty()) ? ThemeAdjustedColor( p.msgOutReplyBarColor()->c, CountAverageColor(descriptor.bubblesData.colors)) @@ -230,6 +251,55 @@ void ChatTheme::adjustPalette(const ChatThemeDescriptor &descriptor) { adjust(p.historyCallArrowOutFg(), by); adjust(p.historyFileOutIconFg(), by); } + auto outBgColors = descriptor.bubblesData.colors; + if (outBgColors.empty()) { + outBgColors.push_back(p.msgOutBg()->c); + } + const auto colors = { + p.msgOutServiceFg(), + p.msgOutDateFg(), + p.msgFileThumbLinkOutFg(), + p.msgFileOutBg(), + p.msgOutReplyBarColor(), + p.msgWaveformOutActive(), + p.historyTextOutFg(), + p.mediaOutFg(), + p.historyLinkOutFg(), + p.msgOutMonoFg(), + p.historyOutIconFg(), + p.historyCallArrowOutFg(), + }; + const auto minimal = [&](const QColor &with) { + auto result = kMaxContrastValue; + for (const auto &color : colors) { + result = std::min(result, CountContrast(color->c, with)); + } + return result; + }; + const auto withBg = [&](auto &&count) { + auto result = kMaxContrastValue; + for (const auto &bg : outBgColors) { + result = std::min(result, count(bg)); + } + return result; + }; + const auto singleWithBg = [&](const QColor &c) { + return withBg([&](const QColor &with) { + return CountContrast(c, with); + }); + }; + if (withBg(minimal) < kMinAcceptableContrast) { + const auto white = QColor(255, 255, 255); + const auto black = QColor(0, 0, 0); + // This one always gives black :) + //const auto now = (singleWithBg(white) >= singleWithBg(black)) + // ? white + // : black; + const auto now = descriptor.basedOnDark ? white : black; + for (const auto &color : colors) { + set(color, now); + } + } } void ChatTheme::set(const style::color &my, const QColor &color) { diff --git a/Telegram/SourceFiles/ui/chat/chat_theme.h b/Telegram/SourceFiles/ui/chat/chat_theme.h index 53e5fc3cd..495708697 100644 --- a/Telegram/SourceFiles/ui/chat/chat_theme.h +++ b/Telegram/SourceFiles/ui/chat/chat_theme.h @@ -101,6 +101,7 @@ struct ChatThemeDescriptor { Fn preparePalette; ChatThemeBackgroundData backgroundData; ChatThemeBubblesData bubblesData; + bool basedOnDark = false; }; class ChatTheme final : public base::has_weak_ptr { diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index e5ff66fdc..2ce860f41 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -1452,6 +1452,7 @@ void SessionController::cacheChatTheme(const Data::CloudTheme &data) { data.accentColor), .backgroundData = backgroundData(theme), .bubblesData = PrepareBubblesData(data), + .basedOnDark = data.basedOnDark, }; crl::async([ this,