diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 462e737c6..e2a19b5ff 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -134,18 +134,20 @@ PRIVATE ayu/ui/sections/edited/edited_log_item.h ayu/ui/sections/edited/edited_log_section.cpp ayu/ui/sections/edited/edited_log_section.h - ayu/ui/boxes/voice_confirmation_box.cpp - ayu/ui/boxes/voice_confirmation_box.h - ayu/ui/boxes/message_history_box.cpp - ayu/ui/boxes/message_history_box.h - ayu/ui/boxes/confirmation_box.cpp - ayu/ui/boxes/confirmation_box.h + ayu/ui/boxes/server_read_confirmation_box.cpp + ayu/ui/boxes/server_read_confirmation_box.h ayu/ui/boxes/edit_deleted_mark.cpp ayu/ui/boxes/edit_deleted_mark.h ayu/ui/boxes/edit_edited_mark.cpp ayu/ui/boxes/edit_edited_mark.h ayu/ui/boxes/font_selector.cpp ayu/ui/boxes/font_selector.h + ayu/ui/boxes/theme_selector_box.cpp + ayu/ui/boxes/theme_selector_box.h + ayu/ui/boxes/message_shot_box.cpp + ayu/ui/boxes/message_shot_box.h + ayu/ui/components/image_view.cpp + ayu/ui/components/image_view.h ayu/sync/ayu_sync_controller.cpp ayu/sync/ayu_sync_controller.h ayu/sync/models.h @@ -164,6 +166,8 @@ PRIVATE ayu/features/streamer_mode/streamer_mode_windows.cpp ayu/features/streamer_mode/streamer_mode_linux.cpp ayu/features/streamer_mode/streamer_mode.h + ayu/features/messageshot/message_shot.cpp + ayu/features/messageshot/message_shot.h ayu/database/entities.h ayu/database/ayu_database.cpp ayu/database/ayu_database.h diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 772a0c2a5..5373b3dc9 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4799,6 +4799,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_MonospaceFont" = "Monospace font"; "ayu_FontDefault" = "Default"; "ayu_CustomizeFontTitle" = "Customize font"; +"ayu_MessageShotTopBarText" = "Shot"; +"ayu_MessageShotPreview" = "Preview"; +"ayu_MessageShotPreferences" = "Preferences"; +"ayu_MessageShotCopy" = "Copy"; +"ayu_MessageShotSave" = "Save"; +"ayu_MessageShotTheme" = "Theme"; +"ayu_MessageShotThemeDefault" = "Default"; +"ayu_MessageShotThemeSelectTitle" = "Select message theme"; +"ayu_MessageShotThemeApply" = "Apply"; +"ayu_MessageShotShowDate" = "Show date"; +"ayu_MessageShotShowReactions" = "Show reactions"; +"ayu_MessageShotShowColorfulReplies" = "Show colorful replies"; +"ayu_SendAsSticker" = "Send as Sticker"; "ayu_AyuForwardStatusForwarding" = "Forwarding messages…"; "ayu_AyuForwardStatusLoadingMedia" = "Loading media…"; "ayu_AyuForwardForwardingDescription" = "Please keep this window open while AyuGram is forwarding your messages."; diff --git a/Telegram/SourceFiles/ayu/features/messageshot/message_shot.cpp b/Telegram/SourceFiles/ayu/features/messageshot/message_shot.cpp new file mode 100644 index 000000000..8ef42d077 --- /dev/null +++ b/Telegram/SourceFiles/ayu/features/messageshot/message_shot.cpp @@ -0,0 +1,425 @@ +// This is the source code of AyuGram for Desktop. +// +// We do not and cannot prevent the use of our code, +// but be respectful and credit the original author. +// +// Copyright @Radolyn, 2023 +#include "message_shot.h" + +#include "styles/style_layers.h" + +#include "data/data_cloud_themes.h" +#include "data/data_photo.h" +#include "data/data_session.h" +#include "history/history_inner_widget.h" +#include "history/view/media/history_view_media.h" +#include "main/main_session.h" +#include "data/data_peer.h" +#include "history/history.h" +#include "qguiapplication.h" +#include "ayu/ui/boxes/message_shot_box.h" +#include "boxes/abstract_box.h" +#include "ui/chat/chat_theme.h" +#include "ui/painter.h" +#include "history/history_item.h" +#include "history/view/history_view_element.h" +#include "history/view/history_view_message.h" +#include "styles/style_boxes.h" +#include "styles/style_chat.h" +#include "styles/style_ayu_styles.h" +#include "ui/layers/box_content.h" +#include "ui/effects/path_shift_gradient.h" + +namespace AyuFeatures::MessageShot +{ + +ShotConfig *config; + +Window::Theme::EmbeddedType defaultSelected = Window::Theme::EmbeddedType(-1); +std::optional defaultSelectedColor; + +std::optional customSelected; + +rpl::event_stream<> resetDefaultSelectedStream; +rpl::event_stream<> resetCustomSelectedStream; + +bool takingShot = false; +bool choosingTheme = false; + +rpl::event_stream themeChosenStream; +rpl::event_stream paletteChosenStream; + +void setShotConfig(ShotConfig &config) +{ + MessageShot::config = &config; +} + +void resetShotConfig() +{ + config = nullptr; +} + +ShotConfig getShotConfig() +{ + return *config; +} + +void setDefaultSelected(const Window::Theme::EmbeddedType type) +{ + resetCustomSelected(); + defaultSelected = type; +} + +Window::Theme::EmbeddedType getSelectedFromDefault() +{ + return defaultSelected; +} + +void setDefaultSelectedColor(const QColor color) +{ + resetCustomSelected(); + defaultSelectedColor = color; +} + +std::optional getSelectedColorFromDefault() +{ + return defaultSelectedColor; +} + +void setCustomSelected(const Data::CloudTheme theme) +{ + resetDefaultSelected(); + customSelected = theme; +} + +std::optional getSelectedFromCustom() +{ + return customSelected; +} + +void resetDefaultSelected() +{ + defaultSelected = Window::Theme::EmbeddedType(-1); + resetDefaultSelectedStream.fire({}); +} + +void resetCustomSelected() +{ + customSelected = std::nullopt; + resetCustomSelectedStream.fire({}); +} + +rpl::producer<> resetDefaultSelectedEvents() +{ + return resetDefaultSelectedStream.events(); +} + +rpl::producer<> resetCustomSelectedEvents() +{ + return resetCustomSelectedStream.events(); +} + +bool ignoreRender(RenderPart part) +{ + if (!config) { + return false; + } + + const auto ignoreDate = !config->showDate; + const auto ignoreReactions = !config->showReactions; + + return isTakingShot() && + ((part == RenderPart::Date && ignoreDate) || + (part == RenderPart::Reactions && ignoreReactions)); +} + +bool isTakingShot() +{ + return takingShot; +} + +bool setChoosingTheme(bool val) +{ + choosingTheme = val; + return choosingTheme; +} + +bool isChoosingTheme() +{ + return choosingTheme; +} + +rpl::producer themeChosen() +{ + return themeChosenStream.events(); +} + +void setTheme(Data::CloudTheme theme) +{ + themeChosenStream.fire(std::move(theme)); +} + +void setPalette(style::palette &palette) +{ + paletteChosenStream.fire(std::move(palette)); +} + +rpl::producer paletteChosen() +{ + return paletteChosenStream.events(); +} + +class MessageShotDelegate final : public HistoryView::DefaultElementDelegate +{ +public: + MessageShotDelegate( + not_null parent, + not_null st, + Fn update); + + bool elementAnimationsPaused() override; + not_null elementPathShiftGradient() override; + HistoryView::Context elementContext() override; + bool elementIsChatWide() override; + +private: + const not_null _parent; + const std::unique_ptr _pathGradient; +}; + +MessageShotDelegate::MessageShotDelegate( + not_null parent, + not_null st, + Fn update) + : _parent(parent) + , _pathGradient(HistoryView::MakePathShiftGradient(st, update)) +{ +} + +bool MessageShotDelegate::elementAnimationsPaused() +{ + return _parent->window()->isActiveWindow(); +} + +auto MessageShotDelegate::elementPathShiftGradient() + -> not_null +{ + return _pathGradient.get(); +} + +HistoryView::Context MessageShotDelegate::elementContext() +{ + return HistoryView::Context::AdminLog; +} + +bool MessageShotDelegate::elementIsChatWide() +{ + return true; +} + +QImage removePadding(const QImage &original) +{ + if (original.isNull()) { + return {}; + } + + int minX = original.width(); + int minY = original.height(); + int maxX = 0; + int maxY = 0; + + for (int x = 0; x < original.width(); ++x) { + for (int y = 0; y < original.height(); ++y) { + if (qAlpha(original.pixel(x, y)) != 0) { + minX = std::min(minX, x); + minY = std::min(minY, y); + maxX = std::max(maxX, x); + maxY = std::max(maxY, y); + } + } + } + + if (minX > maxX || minY > maxY) { + LOG(("Image is fully transparent ?")); + return {}; + } + + QRect bounds(minX, minY, maxX - minX + 1, maxY - minY + 1); + return original.copy(bounds); +} + +QImage addPadding(const QImage &original, int padding) +{ + if (original.isNull()) { + return {}; + } + + QImage paddedImage( + original.width() + padding * 2 * style::DevicePixelRatio(), + original.height() + padding * 2 * style::DevicePixelRatio(), + QImage::Format_ARGB32_Premultiplied + ); + paddedImage.fill(Qt::transparent); + + Painter painter(&paddedImage); + painter.drawImage(padding, padding, original); + painter.end(); + + return paddedImage; +} + +QImage Make(not_null box, const ShotConfig &config) +{ + const auto controller = config.controller; + const auto st = config.st; + const auto messages = config.messages; + + if (messages.empty()) { + return {}; + } + + takingShot = true; + + auto delegate = std::make_unique(box, + st.get(), + [=] + { + box->update(); + }); + + std::unordered_map, std::shared_ptr> createdViews; + createdViews.reserve(messages.size()); + for (const auto &message : messages) { + createdViews.emplace(message, message->createView(delegate.get())); + } + + auto getView = [=](not_null msg) + { + return createdViews.at(msg).get(); + }; + + // recalculate blocks + if (messages.size() > 1) { + auto currentMsg = messages[0].get(); + + for (auto i = 1; i != messages.size(); ++i) { + const auto nextMsg = messages[i].get(); + if (getView(nextMsg)->isHidden()) { + getView(nextMsg)->setDisplayDate(false); + } + else { + const auto viewDate = getView(currentMsg)->dateTime(); + const auto nextDate = getView(nextMsg)->dateTime(); + getView(nextMsg)->setDisplayDate(nextDate.date() != viewDate.date()); + auto attached = getView(nextMsg)->computeIsAttachToPrevious(getView(currentMsg)); + getView(nextMsg)->setAttachToPrevious(attached, getView(currentMsg)); + getView(currentMsg)->setAttachToNext(attached, getView(nextMsg)); + currentMsg = nextMsg; + } + } + + getView(messages[messages.size() - 1])->setAttachToNext(false); + } + else { + getView(messages[0])->setAttachToPrevious(false); + getView(messages[0])->setAttachToNext(false); + } + + // calculate the size of the image + int width = st::msgMaxWidth + (st::boxPadding.left() + st::boxPadding.right()); + int height = 0; + + for (int i = 0; i < messages.size(); i++) { + const auto &message = messages[i]; + const auto view = getView(message); + + view->itemDataChanged(); // refresh reactions + height += view->resizeGetHeight(width); + } + + // width *= style::DevicePixelRatio(); + height *= style::DevicePixelRatio(); + + // create the image + QImage image(width, height, QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::transparent); + + const auto viewport = QRect(0, 0, width, height); + + Painter p(&image); + + // draw the messages + int y = 0; + for (int i = 0; i < messages.size(); i++) { + const auto &message = messages[i]; + const auto view = getView(message); + + const auto displayUserpic = view->displayFromPhoto() || message->isPost(); + + const auto rect = QRect(0, y, width, view->height()); + + auto context = controller->defaultChatTheme()->preparePaintContext( + st.get(), + viewport, + rect, + true); + + // hides too much + // if (AyuFeatures::MessageShot::ignoreRender(AyuFeatures::MessageShot::RenderPart::Date)) { + // context.skipDrawingParts = Ui::ChatPaintContext::SkipDrawingParts::Surrounding; + // } + + p.translate(0, y); + view->draw(p, context); + p.translate(0, -y); + + if (displayUserpic) { + const auto picX = st::msgMargin.left(); + const auto picY = y + view->height() - st::msgPhotoSize; + + auto userpicView = + !message->displayFrom()->activeUserpicView().null() + ? message->displayFrom()->activeUserpicView() + : message->displayFrom()->createUserpicView(); + message->displayFrom()->paintUserpic(p, userpicView, picX, picY, st::msgPhotoSize); + } + + y += view->height(); + } + + takingShot = false; + + const auto overlay = addPadding(removePadding(image), 4); + + return overlay; +} + +void Wrapper(not_null widget) +{ + const auto items = widget->getSelectedIds(); + if (items.empty()) { + return; + } + + const auto session = &widget->session(); + const auto controller = widget->session().tryResolveWindow(); + if (!controller) { + return; + } + + const auto messages = ranges::views::all(items) + | ranges::views::transform([=](const auto item) + { + return gsl::not_null(session->data().message(item)); + }) + | ranges::to_vector; + + const AyuFeatures::MessageShot::ShotConfig config = { + controller, + std::make_shared(controller->chatStyle()), + messages, + }; + auto box = Box(config); + Ui::show(std::move(box)); +} +} diff --git a/Telegram/SourceFiles/ayu/features/messageshot/message_shot.h b/Telegram/SourceFiles/ayu/features/messageshot/message_shot.h new file mode 100644 index 000000000..fad4e06b6 --- /dev/null +++ b/Telegram/SourceFiles/ayu/features/messageshot/message_shot.h @@ -0,0 +1,69 @@ +// This is the source code of AyuGram for Desktop. +// +// We do not and cannot prevent the use of our code, +// but be respectful and credit the original author. +// +// Copyright @Radolyn, 2023 +#pragma once + +#include "window/window_session_controller.h" +#include "history/view/history_view_list_widget.h" +#include "ui/chat/chat_style.h" +#include "window/themes/window_themes_embedded.h" + +namespace AyuFeatures::MessageShot { + +struct ShotConfig { + not_null controller; + std::shared_ptr st; + std::vector> messages; + + bool showDate; + bool showReactions; +}; + +enum RenderPart +{ + Date, + Reactions, +}; + +void setShotConfig(ShotConfig& config); +void resetShotConfig(); +ShotConfig getShotConfig(); + +// for default themes +void setDefaultSelected(Window::Theme::EmbeddedType type); +Window::Theme::EmbeddedType getSelectedFromDefault(); + +void setDefaultSelectedColor(QColor color); +std::optional getSelectedColorFromDefault(); + +// for custom themes +void setCustomSelected(Data::CloudTheme theme); +std::optional getSelectedFromCustom(); + +// resets +void resetDefaultSelected(); +void resetCustomSelected(); + +rpl::producer<> resetDefaultSelectedEvents(); +rpl::producer<> resetCustomSelectedEvents(); + +bool ignoreRender(RenderPart part); +bool isTakingShot(); + +bool isChoosingTheme(); +bool setChoosingTheme(bool val); + +void setTheme(Data::CloudTheme theme); +rpl::producer themeChosen(); + +void setPalette(style::palette& palette); +rpl::producer paletteChosen(); + +QImage Make(not_null box, const ShotConfig &config); + +void Wrapper(not_null widget); + +} diff --git a/Telegram/SourceFiles/ayu/ui/ayu_styles.style b/Telegram/SourceFiles/ayu/ui/ayu_styles.style index f6a99976f..f27046f4b 100644 --- a/Telegram/SourceFiles/ayu/ui/ayu_styles.style +++ b/Telegram/SourceFiles/ayu/ui/ayu_styles.style @@ -23,3 +23,5 @@ cpSpacingY: 8px; cpIconSize: 64px; recentStickersLimitPadding: margins(22px, 4px, 22px, 8px); +imageViewPadding: margins(22px, 10px, 22px, 10px); +imageViewInnerPadding: margins(16px, 16px, 16px, 16px); diff --git a/Telegram/SourceFiles/ayu/ui/boxes/font_selector.h b/Telegram/SourceFiles/ayu/ui/boxes/font_selector.h index 145f4ebfc..63486a91c 100644 --- a/Telegram/SourceFiles/ayu/ui/boxes/font_selector.h +++ b/Telegram/SourceFiles/ayu/ui/boxes/font_selector.h @@ -6,7 +6,6 @@ // Copyright @Radolyn, 2023 #pragma once -#include "lang/lang_cloud_manager.h" #include "boxes/abstract_box.h" #include "base/binary_guard.h" diff --git a/Telegram/SourceFiles/ayu/ui/boxes/message_history_box.cpp b/Telegram/SourceFiles/ayu/ui/boxes/message_history_box.cpp deleted file mode 100644 index f8946ec29..000000000 --- a/Telegram/SourceFiles/ayu/ui/boxes/message_history_box.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// This is the source code of AyuGram for Desktop. -// -// We do not and cannot prevent the use of our code, -// but be respectful and credit the original author. -// -// Copyright @Radolyn, 2023 -#include "message_history_box.h" -#include "ayu/ayu_settings.h" -#include "ayu/database/ayu_database.h" -#include "ayu/messages/ayu_messages_controller.h" - -#include "history/history.h" -#include "settings/settings_common.h" -#include "styles/style_boxes.h" -#include "styles/style_layers.h" -#include "ui/effects/scroll_content_shadow.h" -#include "ui/vertical_list.h" - -using namespace Settings; - -namespace AyuUi -{ - -MessageHistoryBox::MessageHistoryBox(QWidget *, HistoryItem *item) - : _content(this), _scroll(base::make_unique_q(this, st::boxScroll)) -{ - setupControls(); - addEditedMessagesToLayout(item); -} - -void MessageHistoryBox::setupControls() -{ - _content.create(this); - - _content->resizeToWidth(st::boxWideWidth); - _content->moveToLeft(0, 0); - - _content->heightValue( - ) | start_to_stream(_contentHeight, _content->lifetime()); - - _scroll->setOwnedWidget( - object_ptr::fromRaw(_content)); -} - -void MessageHistoryBox::resizeEvent(QResizeEvent *e) -{ - _scroll->resize(width(), height() - st::boxPhotoPadding.top() - st::boxPadding.bottom()); - _scroll->move(0, st::boxPadding.top()); - - if (_content) { - _content->resize(_scroll->width(), _content->height()); - } -} - -void MessageHistoryBox::prepare() -{ - setTitle(tr::ayu_EditsHistoryTitle()); - - setDimensions(st::boxWideWidth, 900); - SetupShadowsToScrollContent(this, _scroll, _contentHeight.events()); -} - -void MessageHistoryBox::addEditedMessagesToLayout(HistoryItem *item) -{ - auto messages = AyuMessages::getInstance().getEditedMessages(item); - if (messages.empty()) { - return; - } - - for (const auto &message : messages) { - AddSkip(_content); - AddDividerText(_content, rpl::single(QString::fromStdString(message.text))); - AddSkip(_content); - } -} - -} diff --git a/Telegram/SourceFiles/ayu/ui/boxes/message_history_box.h b/Telegram/SourceFiles/ayu/ui/boxes/message_history_box.h deleted file mode 100644 index b705c0bcf..000000000 --- a/Telegram/SourceFiles/ayu/ui/boxes/message_history_box.h +++ /dev/null @@ -1,38 +0,0 @@ -// This is the source code of AyuGram for Desktop. -// -// We do not and cannot prevent the use of our code, -// but be respectful and credit the original author. -// -// Copyright @Radolyn, 2023 -#pragma once - -#include "history/history_item.h" -#include "ui/layers/box_content.h" -#include "ui/widgets/scroll_area.h" -#include "ui/wrap/vertical_layout.h" - -namespace AyuUi -{ - -class MessageHistoryBox : public Ui::BoxContent -{ -public: - MessageHistoryBox(QWidget *, HistoryItem *item); - -protected: - void prepare() override; - - void resizeEvent(QResizeEvent *e) override; - -private: - void setupControls(); - - void addEditedMessagesToLayout(HistoryItem *item); - - object_ptr _content; - const base::unique_qptr _scroll; - - rpl::event_stream _contentHeight; -}; - -} diff --git a/Telegram/SourceFiles/ayu/ui/boxes/message_shot_box.cpp b/Telegram/SourceFiles/ayu/ui/boxes/message_shot_box.cpp new file mode 100644 index 000000000..f019e3b33 --- /dev/null +++ b/Telegram/SourceFiles/ayu/ui/boxes/message_shot_box.cpp @@ -0,0 +1,202 @@ +// This is the source code of AyuGram for Desktop. +// +// We do not and cannot prevent the use of our code, +// but be respectful and credit the original author. +// +// Copyright @Radolyn, 2023 +#include "message_shot_box.h" + +#include +#include +#include "styles/style_ayu_styles.h" + +#include "boxes/abstract_box.h" +#include "ayu/ui/components/image_view.h" +#include "core/core_settings.h" +#include "data/data_session.h" +#include "lang_auto.h" +#include "main/main_session.h" +#include "settings/settings_common.h" +#include "styles/style_layers.h" +#include "styles/style_settings.h" +#include "ui/widgets/buttons.h" +#include "ui/wrap/vertical_layout.h" +#include "ui/vertical_list.h" +#include "theme_selector_box.h" +#include "ayu/ayu_settings.h" + +MessageShotBox::MessageShotBox( + QWidget *parent, + AyuFeatures::MessageShot::ShotConfig config) + : _config(std::move(config)) +{ +} + +void MessageShotBox::prepare() +{ + setupContent(); +} + +void MessageShotBox::setupContent() +{ + _selectedPalette = std::make_shared(); + + const auto settings = &AyuSettings::getInstance(); + const auto savedShowColorfulReplies = !settings->simpleQuotesAndReplies; + + using namespace Settings; + + AyuFeatures::MessageShot::setShotConfig(_config); + + setTitle(rpl::single(QString("Message Shot"))); + + auto wrap = object_ptr(this); + const auto content = wrap.data(); + setInnerWidget(object_ptr(this, std::move(wrap))); + + AddSubsectionTitle(content, tr::ayu_MessageShotPreview()); + + const auto imageView = content->add(object_ptr(content), st::imageViewPadding); + + AddSkip(content); + AddDivider(content); + AddSkip(content); + AddSubsectionTitle(content, tr::ayu_MessageShotPreferences()); + + const auto updatePreview = [=] + { + const auto image = AyuFeatures::MessageShot::Make(this, _config); + imageView->setImage(image); + }; + + auto selectedTheme = + content->lifetime().make_state >(tr::ayu_MessageShotThemeDefault(tr::now)); + + AddButtonWithLabel( + content, + tr::ayu_MessageShotTheme(), + selectedTheme->value(), + st::settingsButtonNoIcon + )->addClickHandler( + [=] + { + AyuFeatures::MessageShot::setChoosingTheme(true); + + auto box = Box(_config.controller); + box->paletteSelected() | rpl::start_with_next( + [=](const style::palette &palette) mutable + { + _selectedPalette->reset(); + _selectedPalette->load(palette.save()); + + _config.st = std::make_shared( + _selectedPalette.get()); + + updatePreview(); + }, + content->lifetime()); + + box->themeNameChanged() | rpl::start_with_next( + [=](const QString &name) + { + selectedTheme->force_assign(name); + }, + content->lifetime()); + + box->boxClosing() | rpl::start_with_next( + [=] + { + AyuFeatures::MessageShot::setChoosingTheme(false); + }, + content->lifetime()); + + Ui::show(std::move(box), Ui::LayerOption::KeepOther); + }); + + AddButtonWithIcon( + content, + tr::ayu_MessageShotShowDate(), + st::settingsButtonNoIcon + )->toggleOn(rpl::single(false) + )->toggledValue( + ) | start_with_next( + [=](bool enabled) + { + _config.showDate = enabled; + + updatePreview(); + }, + content->lifetime()); + + AddButtonWithIcon( + content, + tr::ayu_MessageShotShowReactions(), + st::settingsButtonNoIcon + )->toggleOn(rpl::single(false) + )->toggledValue( + ) | start_with_next( + [=](bool enabled) + { + _config.showReactions = enabled; + + updatePreview(); + }, + content->lifetime()); + + AddButtonWithIcon( + content, + tr::ayu_MessageShotShowColorfulReplies(), + st::settingsButtonNoIcon + )->toggleOn(rpl::single(savedShowColorfulReplies) + )->toggledValue( + ) | start_with_next( + [=](bool enabled) + { + const auto settings = &AyuSettings::getInstance(); + settings->set_simpleQuotesAndReplies(!enabled); + + _config.st = std::make_shared(_config.st.get()); + updatePreview(); + }, + content->lifetime()); + + AddSkip(content); + + addButton(tr::ayu_MessageShotSave(), + [=] + { + const auto image = imageView->getImage(); + const auto path = QFileDialog::getSaveFileName( + this, + tr::lng_save_file(tr::now), + QString(), + "*.png"); + + if (!path.isEmpty()) { + image.save(path); + } + }); + addButton(tr::ayu_MessageShotCopy(), + [=] + { + QGuiApplication::clipboard()->setImage(imageView->getImage()); + }); + + updatePreview(); + + const auto boxWidth = imageView->getImage().width() + (st::boxPadding.left() + st::boxPadding.right()) * 4; + + boxClosing() | rpl::start_with_next( + [=] + { + AyuFeatures::MessageShot::resetCustomSelected(); + AyuFeatures::MessageShot::resetDefaultSelected(); + AyuFeatures::MessageShot::resetShotConfig(); + + const auto settings = &AyuSettings::getInstance(); + settings->set_simpleQuotesAndReplies(!savedShowColorfulReplies); + }, + content->lifetime()); + + setDimensionsToContent(boxWidth, content); +} diff --git a/Telegram/SourceFiles/ayu/ui/boxes/message_shot_box.h b/Telegram/SourceFiles/ayu/ui/boxes/message_shot_box.h new file mode 100644 index 000000000..b98019c58 --- /dev/null +++ b/Telegram/SourceFiles/ayu/ui/boxes/message_shot_box.h @@ -0,0 +1,25 @@ +// This is the source code of AyuGram for Desktop. +// +// We do not and cannot prevent the use of our code, +// but be respectful and credit the original author. +// +// Copyright @Radolyn, 2023 +#pragma once + +#include "ayu/features/messageshot/message_shot.h" +#include "ui/layers/box_content.h" + +class MessageShotBox : public Ui::BoxContent { +public: + MessageShotBox(QWidget* parent, AyuFeatures::MessageShot::ShotConfig config); + +protected: + void prepare() override; + +private: + void setupContent(); + + AyuFeatures::MessageShot::ShotConfig _config; + std::shared_ptr _selectedPalette; + +}; diff --git a/Telegram/SourceFiles/ayu/ui/boxes/confirmation_box.cpp b/Telegram/SourceFiles/ayu/ui/boxes/server_read_confirmation_box.cpp similarity index 93% rename from Telegram/SourceFiles/ayu/ui/boxes/confirmation_box.cpp rename to Telegram/SourceFiles/ayu/ui/boxes/server_read_confirmation_box.cpp index f04dee7da..4fe7398e6 100644 --- a/Telegram/SourceFiles/ayu/ui/boxes/confirmation_box.cpp +++ b/Telegram/SourceFiles/ayu/ui/boxes/server_read_confirmation_box.cpp @@ -4,15 +4,14 @@ // but be respectful and credit the original author. // // Copyright @Radolyn, 2023 -#include "confirmation_box.h" +#include "server_read_confirmation_box.h" + #include "lang_auto.h" #include "ayu/ayu_settings.h" #include "ayu/utils/telegram_helpers.h" #include "data/data_session.h" #include "main/main_session.h" #include "styles/style_layers.h" -#include "ui/text/text_utilities.h" -#include "window/window_peer_menu.h" #include "window/window_session_controller.h" namespace AyuUi diff --git a/Telegram/SourceFiles/ayu/ui/boxes/confirmation_box.h b/Telegram/SourceFiles/ayu/ui/boxes/server_read_confirmation_box.h similarity index 100% rename from Telegram/SourceFiles/ayu/ui/boxes/confirmation_box.h rename to Telegram/SourceFiles/ayu/ui/boxes/server_read_confirmation_box.h diff --git a/Telegram/SourceFiles/ayu/ui/boxes/theme_selector_box.cpp b/Telegram/SourceFiles/ayu/ui/boxes/theme_selector_box.cpp new file mode 100644 index 000000000..c7160d8f0 --- /dev/null +++ b/Telegram/SourceFiles/ayu/ui/boxes/theme_selector_box.cpp @@ -0,0 +1,190 @@ +// This is the source code of AyuGram for Desktop. +// +// We do not and cannot prevent the use of our code, +// but be respectful and credit the original author. +// +// Copyright @Radolyn, 2023 +#include "theme_selector_box.h" + +#include "data/data_document.h" +#include "data/data_document_media.h" +#include "data/data_file_origin.h" +#include "data/data_session.h" +#include "lang_auto.h" +#include "main/main_session.h" +#include "settings/settings_chat.h" +#include "styles/style_layers.h" +#include "styles/style_settings.h" +#include "ui/widgets/buttons.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/wrap/vertical_layout.h" +#include "window/themes/window_theme.h" +#include "window/themes/window_theme_preview.h" +#include "ui/vertical_list.h" +#include "window/themes/window_themes_cloud_list.h" +#include "ayu/features/messageshot/message_shot.h" + +ThemeSelectorBox::ThemeSelectorBox( + QWidget *parent, + not_null controller) + : _controller(controller) +{ +} + +rpl::producer ThemeSelectorBox::paletteSelected() +{ + return _palettes.events(); +} + +rpl::producer ThemeSelectorBox::themeNameChanged() +{ + return _themeNames.events(); +} + +void ThemeSelectorBox::prepare() +{ + setupContent(); +} + +void ThemeSelectorBox::setupContent() +{ + using namespace Settings; + + setTitle(tr::ayu_MessageShotThemeSelectTitle()); + + auto wrap2 = object_ptr(this); + const auto container = wrap2.data(); + + setInnerWidget(object_ptr( + this, + std::move(wrap2))); + + AddSubsectionTitle(container, tr::lng_settings_themes()); + AddSkip(container, st::settingsThemesTopSkip); + + Settings::SetupDefaultThemes(&_controller->window(), container); + + AddSkip(container); + + using namespace Window::Theme; + using namespace rpl::mappers; + + const auto wrap = container->add( + object_ptr >( + container, + object_ptr(container)) + )->setDuration(0); + const auto inner = wrap->entity(); + + AddDivider(inner); + AddSkip(inner); + + const auto title = AddSubsectionTitle( + inner, + tr::lng_settings_bg_cloud_themes()); + const auto showAll = Ui::CreateChild( + inner, + tr::lng_settings_bg_show_all(tr::now)); + + rpl::combine( + title->topValue(), + inner->widthValue(), + showAll->widthValue() + ) | rpl::start_with_next([=](int top, int outerWidth, int width) + { + showAll->moveToRight( + st::defaultSubsectionTitlePadding.left(), + top, + outerWidth); + }, + showAll->lifetime()); + + Ui::AddSkip(inner, st::settingsThemesTopSkip); + + const auto list = inner->lifetime().make_state( + inner, + _controller); + inner->add( + list->takeWidget(), + style::margins( + st::settingsButtonNoIcon.padding.left(), + 0, + st::settingsButtonNoIcon.padding.right(), + 0)); + + list->allShown( + ) | rpl::start_with_next([=](bool shown) + { + showAll->setVisible(!shown); + }, + showAll->lifetime()); + + showAll->addClickHandler([=] + { + list->showAll(); + }); + + wrap->setDuration(0)->toggleOn(list->empty() | rpl::map(!_1)); + + _controller->session().data().cloudThemes().refresh(); + + AyuFeatures::MessageShot::themeChosen( + ) | rpl::start_with_next( + [=](Data::CloudTheme theme) + { + const auto document = _controller->session().data().document(theme.documentId); + const auto documentView = document->createMediaView(); + + document->save( + Data::FileOriginTheme(theme.id, theme.accessHash), + QString()); + + const auto innerCallback = [=] + { + auto preview = Window::Theme::PreviewFromFile( + documentView->bytes(), + document->location().name(), + theme); + + _selectedPalette = preview->instance.palette; + + auto name = theme.title; + _themeNames.fire(std::move(name)); + }; + + if (documentView->loaded()) { + innerCallback(); + } + else { + _controller->session().downloaderTaskFinished( + ) | rpl::filter( + [=] + { + return documentView->loaded(); + }) | rpl::start_with_next( + [=] + { + innerCallback(); + }, + lifetime()); + } + }, + lifetime()); + + AyuFeatures::MessageShot::paletteChosen( + ) | rpl::start_with_next([=](const auto &palette) + { + _themeNames.fire(tr::ayu_MessageShotThemeDefault(tr::now)); + _selectedPalette = palette; + }, + lifetime()); + + addButton(tr::ayu_MessageShotThemeApply(), + [=] + { + _palettes.fire(std::move(_selectedPalette)); + closeBox(); + }); + + setDimensionsToContent(st::boxWidth, container); +} diff --git a/Telegram/SourceFiles/ayu/ui/boxes/theme_selector_box.h b/Telegram/SourceFiles/ayu/ui/boxes/theme_selector_box.h new file mode 100644 index 000000000..7b9be2a9e --- /dev/null +++ b/Telegram/SourceFiles/ayu/ui/boxes/theme_selector_box.h @@ -0,0 +1,35 @@ +// This is the source code of AyuGram for Desktop. +// +// We do not and cannot prevent the use of our code, +// but be respectful and credit the original author. +// +// Copyright @Radolyn, 2023 +#pragma once + +#include "ui/style/style_core_palette.h" +#include "ui/layers/box_content.h" +#include "window/window_session_controller.h" + +using Callback = Fn; + +class ThemeSelectorBox : public Ui::BoxContent { +public: + ThemeSelectorBox(QWidget* parent, not_null controller); + + rpl::producer paletteSelected(); + rpl::producer themeNameChanged(); + +protected: + void prepare() override; + +private: + void setupContent(); + + not_null _controller; + + rpl::event_stream _palettes; + rpl::event_stream _themeNames; + + style::palette _selectedPalette; + +}; diff --git a/Telegram/SourceFiles/ayu/ui/boxes/voice_confirmation_box.cpp b/Telegram/SourceFiles/ayu/ui/boxes/voice_confirmation_box.cpp deleted file mode 100644 index d03db95f8..000000000 --- a/Telegram/SourceFiles/ayu/ui/boxes/voice_confirmation_box.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// This is the source code of AyuGram for Desktop. -// -// We do not and cannot prevent the use of our code, -// but be respectful and credit the original author. -// -// Copyright @Radolyn, 2023 -#include "ui/boxes/confirm_box.h" - -#include "voice_confirmation_box.h" -#include "lang/lang_keys.h" -#include "styles/style_layers.h" -#include "ui/widgets/buttons.h" - -namespace AyuUi -{ - -void VoiceConfirmBox(not_null box, Ui::ConfirmBoxArgs &&args) -{ - const auto weak = MakeWeak(box); - const auto lifetime = box->lifetime().make_state(); - - v::match(args.text, [](v::null_t) - { - }, [&](auto &&) - { - const auto label = box->addRow( - object_ptr( - box.get(), - v::text::take_marked(std::move(args.text)), - args.labelStyle ? *args.labelStyle : st::boxLabel), - st::boxPadding); - if (args.labelFilter) { - label->setClickHandlerFilter(std::move(args.labelFilter)); - } - }); - - const auto prepareCallback = [&](Ui::ConfirmBoxArgs::Callback &callback) - { - return [=, confirmed = std::move(callback)]() - { - if (const auto callbackPtr = std::get_if<1>(&confirmed)) { - if (auto callback = (*callbackPtr)) { - callback(); - } - } - else if (const auto callbackPtr = std::get_if<2>(&confirmed)) { - if (auto callback = (*callbackPtr)) { - callback(crl::guard(weak, [=] - { weak->closeBox(); })); - } - } - else if (weak) { - weak->closeBox(); - } - }; - }; - - const auto &defaultButtonStyle = box->getDelegate()->style().button; - - const auto confirmButton = box->addButton( - v::text::take_plain(std::move(args.confirmText), tr::lng_box_ok()), - [=, c = prepareCallback(args.confirmed)]() - { - lifetime->destroy(); - c(); - - weak->closeBox(); - }, - args.confirmStyle ? *args.confirmStyle : defaultButtonStyle); - box->events( - ) | start_with_next([=](not_null e) - { - if ((e->type() != QEvent::KeyPress) || !confirmButton) { - return; - } - const auto k = static_cast(e.get()); - if (k->key() == Qt::Key_Enter || k->key() == Qt::Key_Return) { - confirmButton->clicked(Qt::KeyboardModifiers(), Qt::LeftButton); - } - }, box->lifetime()); - - if (!args.inform) { - const auto cancelButton = box->addButton( - v::text::take_plain(std::move(args.cancelText), tr::lng_cancel()), - crl::guard(weak, [=, c = prepareCallback(args.cancelled)]() - { - lifetime->destroy(); - c(); - }), - args.cancelStyle ? *args.cancelStyle : defaultButtonStyle); - - box->boxClosing( - ) | start_with_next(crl::guard(cancelButton, [=] - { - cancelButton->clicked(Qt::KeyboardModifiers(), Qt::LeftButton); - }), *lifetime); - } - - if (args.strictCancel) { - lifetime->destroy(); - } -} - -object_ptr MakeConfirmBox(Ui::ConfirmBoxArgs &&args) -{ - return Box(VoiceConfirmBox, std::move(args)); -} - -object_ptr MakeInformBox(v::text::data text) -{ - return MakeConfirmBox({ - .text = std::move(text), - .inform = true, - }); -} - -} // namespace AyuUi diff --git a/Telegram/SourceFiles/ayu/ui/boxes/voice_confirmation_box.h b/Telegram/SourceFiles/ayu/ui/boxes/voice_confirmation_box.h deleted file mode 100644 index 059944976..000000000 --- a/Telegram/SourceFiles/ayu/ui/boxes/voice_confirmation_box.h +++ /dev/null @@ -1,23 +0,0 @@ -// This is the source code of AyuGram for Desktop. -// -// We do not and cannot prevent the use of our code, -// but be respectful and credit the original author. -// -// Copyright @Radolyn, 2023 -#pragma once - -#include "ui/boxes/confirm_box.h" -#include "ui/layers/generic_box.h" -#include "ui/text/text_variant.h" - -namespace AyuUi -{ - -void VoiceConfirmBox(not_null box, Ui::ConfirmBoxArgs &&args); - -[[nodiscard]] object_ptr MakeConfirmBox( - Ui::ConfirmBoxArgs &&args); - -[[nodiscard]] object_ptr MakeInformBox(v::text::data text); - -} // namespace Ui diff --git a/Telegram/SourceFiles/ayu/ui/components/image_view.cpp b/Telegram/SourceFiles/ayu/ui/components/image_view.cpp new file mode 100644 index 000000000..007475e43 --- /dev/null +++ b/Telegram/SourceFiles/ayu/ui/components/image_view.cpp @@ -0,0 +1,112 @@ +// This is the source code of AyuGram for Desktop. +// +// We do not and cannot prevent the use of our code, +// but be respectful and credit the original author. +// +// Copyright @Radolyn, 2023 +#include "image_view.h" + +#include "styles/style_ayu_styles.h" + +#include "ayu/utils/telegram_helpers.h" +#include "styles/style_chat.h" +#include "window/themes/window_theme.h" +#include "ui/painter.h" + +ImageView::ImageView(QWidget *parent) + : RpWidget(parent) +{ +} + +void ImageView::setImage(const QImage &image) +{ + if (this->image == image) { + return; + } + + const auto set = [=] { + this->prevImage = this->image; + this->image = image; + + setMinimumSize(image.size().grownBy(st::imageViewInnerPadding)); + + if (this->animation.animating()) { + this->animation.stop(); + } + + if (this->prevImage.isNull()) { + update(); + return; + } + + this->animation.start( + [=] + { update(); }, 0.0, 1.0, 300, anim::easeInCubic); + }; + + if (this->image.isNull()) { + set(); + return; + } + + dispatchToMainThread(set, 100); +} + +QImage ImageView::getImage() const +{ + return image; +} + +void ImageView::paintEvent(QPaintEvent *e) +{ + Painter p(this); +// PainterHighQualityEnabler hq(p); + + auto brush = QBrush(st::boxBg); // copy + + if (Window::Theme::IsNightMode()) { + brush.setColor(brush.color().lighter(120)); + } + else { + brush.setColor(brush.color().darker(105)); + } + + QPainterPath path; + path.addRoundedRect(rect(), st::bubbleRadiusLarge, st::bubbleRadiusLarge); + + p.fillPath(path, brush); + + if (!prevImage.isNull()) { + const auto realRect = rect().marginsRemoved(st::imageViewInnerPadding); + + const auto resizedRect = QRect( + (realRect.width() - prevImage.width()) / 2 + st::imageViewInnerPadding.left(), + (realRect.height() - prevImage.height()) / 2 + st::imageViewInnerPadding.top(), + prevImage.width(), + prevImage.height()); + + const auto opacity = 1.0 - animation.value(1.0); + p.setOpacity(opacity); + p.drawImage(resizedRect, prevImage); + p.setOpacity(1.0); + } + + if (!image.isNull()) { + const auto realRect = rect().marginsRemoved(st::imageViewInnerPadding); + + const auto resizedRect = QRect( + (realRect.width() - image.width()) / 2 + st::imageViewInnerPadding.left(), + (realRect.height() - image.height()) / 2 + st::imageViewInnerPadding.top(), + image.width(), + image.height()); + + const auto opacity = animation.value(1.0); + p.setOpacity(opacity); + p.drawImage(resizedRect, image); + p.setOpacity(1.0); + } +} + +void ImageView::mousePressEvent(QMouseEvent *e) +{ +} diff --git a/Telegram/SourceFiles/ayu/ui/components/image_view.h b/Telegram/SourceFiles/ayu/ui/components/image_view.h new file mode 100644 index 000000000..ac9ad734a --- /dev/null +++ b/Telegram/SourceFiles/ayu/ui/components/image_view.h @@ -0,0 +1,31 @@ +// This is the source code of AyuGram for Desktop. +// +// We do not and cannot prevent the use of our code, +// but be respectful and credit the original author. +// +// Copyright @Radolyn, 2023 +#pragma once + + +#include "ui/rp_widget.h" +#include "ui/effects/animations.h" + +class ImageView : public Ui::RpWidget +{ +public: + ImageView(QWidget *parent); + + void setImage(const QImage& image); + QImage getImage() const; + +protected: + void paintEvent(QPaintEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + +private: + QImage image; + QImage prevImage; + + Ui::Animations::Simple animation; + +}; diff --git a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp index 8478596d1..c741b6829 100644 --- a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp +++ b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp @@ -256,11 +256,14 @@ void AddMessageDetailsAction(not_null menu, HistoryItem *item) if (isSticker) { const auto authorId = media->document()->sticker()->set.id >> 32; - menu2->addAction(Ui::ContextActionStickerAuthor( - menu2->menu(), - &item->history()->session(), - authorId - )); + + if (authorId != 0) { + menu2->addAction(Ui::ContextActionStickerAuthor( + menu2->menu(), + &item->history()->session(), + authorId + )); + } } } }, diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index c0d6a941a..dea7bb8e7 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -65,6 +65,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL // AyuGram includes #include "ayu/ayu_settings.h" #include "base/unixtime.h" +#include namespace { @@ -623,6 +624,36 @@ void SendFilesBox::addMenuButton() { [=] { sendWhenOnline(); }, &_st.tabbed.icons); } + + using ImageInfo = Ui::PreparedFileInformation::Image; + if (_list.files.size() == 1 && std::get_if(&_list.files[0].information->media)) { + _menu->addAction( + tr::ayu_SendAsSticker(tr::now), + [=]() mutable + { + const auto file = std::move(_list.files[0]); + _list.files.clear(); + + const auto sourceImage = std::get_if(&file.information->media); + + QByteArray targetArray; + QBuffer buffer(&targetArray); + buffer.open(QIODevice::WriteOnly); + sourceImage->data.save(&buffer, "WEBP"); + + QImage targetImage; + targetImage.loadFromData(targetArray, "WEBP"); + + addFiles(Storage::PrepareMediaFromImage(std::move(targetImage), + std::move(targetArray), + st::sendMediaPreviewSize)); + _list.overrideSendImagesAsPhotos = false; + initSendWay(); + + send({}, false); + }, + &st::menuIconStickers); + } _menu->popup(QCursor::pos()); return true; }); @@ -1400,7 +1431,7 @@ void SendFilesBox::send( { DEBUG_LOG(("[AyuGram] Scheduling files")); auto current = base::unixtime::now(); - options.scheduled = current + 60; // well, files can be really big... + options.scheduled = current + 60; // well, files can be huge... } if ((_sendType == Api::SendType::Scheduled diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 85d9bce45..8ec138072 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -67,6 +67,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL // AyuGram includes #include "ayu/ayu_settings.h" +#include "ayu/features/messageshot/message_shot.h" #include "ayu/utils/telegram_helpers.h" @@ -2458,7 +2459,7 @@ void HistoryItem::updateReactionsUnknown() { const std::vector &HistoryItem::reactions() const { static const auto kEmpty = std::vector(); - return _reactions ? _reactions->list() : kEmpty; + return _reactions && !AyuFeatures::MessageShot::ignoreRender(AyuFeatures::MessageShot::RenderPart::Reactions) ? _reactions->list() : kEmpty; } bool HistoryItem::reactionsAreTags() const { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 682509c4b..deb64ee7d 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -171,6 +171,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL // AyuGram includes #include "ayu/ayu_settings.h" #include "ayu/utils/telegram_helpers.h" +#include "ayu/features/messageshot/message_shot.h" +#include "ayu/ui/boxes/message_shot_box.h" +#include "boxes/abstract_box.h" namespace { @@ -824,6 +827,10 @@ HistoryWidget::HistoryWidget( ) | rpl::start_with_next([=] { confirmDeleteSelected(); }, _topBar->lifetime()); + _topBar->messageShotSelectionRequest( + ) | rpl::start_with_next([=] { + messageShotSelected(); + }, _topBar->lifetime()); _topBar->clearSelectionRequest( ) | rpl::start_with_next([=] { clearSelected(); @@ -7717,6 +7724,29 @@ void HistoryWidget::confirmDeleteSelected() { controller()->show(std::move(box)); } +void HistoryWidget::messageShotSelected() { + if (!_list) return; + + auto items = getSelectedItems(); + if (items.empty()) { + return; + } + + const auto messages = ranges::views::all(items) + | ranges::views::transform([this](const auto fullId) { + return gsl::not_null(session().data().message(fullId)); + }) + | ranges::to_vector; + + const AyuFeatures::MessageShot::ShotConfig config = { + controller(), + std::make_shared(controller()->chatStyle()), + messages + }; + auto box = Box(config); + Ui::show(std::move(box)); +} + void HistoryWidget::escape() { if (_composeSearch) { _composeSearch->hideAnimated(); diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 34f101d76..89589a023 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -261,6 +261,7 @@ public: void forwardSelected(); void confirmDeleteSelected(); + void messageShotSelected(); void clearSelected(); [[nodiscard]] SendMenu::Type sendMenuType() const; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp index d958139c2..2291b6e4f 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp @@ -42,7 +42,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL // AyuGram includes #include "ayu/ayu_settings.h" -#include "ayu/ui/boxes/voice_confirmation_box.h" #include "boxes/abstract_box.h" @@ -1725,7 +1724,7 @@ void VoiceRecordBar::stopRecording(StopType type, bool ttlBeforeHide) { }); if (settings->voiceConfirmation) { - Ui::show(AyuUi::MakeConfirmBox( + Ui::show(Ui::MakeConfirmBox( { .text = tr::ayu_ConfirmationVoice(), .confirmed = sendVoiceCallback, @@ -1820,7 +1819,7 @@ void VoiceRecordBar::requestToSendWithOptions(Api::SendOptions options) { }); if (settings->voiceConfirmation) { - Ui::show(AyuUi::MakeConfirmBox( + Ui::show(Ui::MakeConfirmBox( { .text = tr::ayu_ConfirmationVoice(), .confirmed = sendVoiceCallback, diff --git a/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp b/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp index 3736b426c..bc20207dd 100644 --- a/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp +++ b/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp @@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL // AyuGram includes #include "ayu/ayu_settings.h" +#include "ayu/features/messageshot/message_shot.h" namespace HistoryView { @@ -132,7 +133,7 @@ TextState BottomInfo::textState( } const auto textWidth = _authorEditedDate.maxWidth(); auto withTicksWidth = textWidth; - if (_data.flags & (Data::Flag::OutLayout | Data::Flag::Sending)) { + if (!AyuFeatures::MessageShot::isTakingShot() && _data.flags & (Data::Flag::OutLayout | Data::Flag::Sending)) { withTicksWidth += st::historySendStateSpace; } if (!_views.isEmpty()) { @@ -263,7 +264,7 @@ void BottomInfo::paint( auto right = position.x() + width(); const auto firstLineBottom = position.y() + st::msgDateFont->height; - if (_data.flags & Data::Flag::OutLayout) { + if (!AyuFeatures::MessageShot::isTakingShot() && _data.flags & Data::Flag::OutLayout) { const auto &icon = (_data.flags & Data::Flag::Sending) ? (inverted ? st->historySendingInvertedIcon() @@ -332,7 +333,7 @@ void BottomInfo::paint( firstLineBottom + st::historyViewsTop, outerWidth); } - if ((_data.flags & Data::Flag::Sending) + if (!AyuFeatures::MessageShot::isTakingShot() && (_data.flags & Data::Flag::Sending) && !(_data.flags & Data::Flag::OutLayout)) { right -= st::historySendStateSpace; const auto &icon = inverted @@ -558,7 +559,7 @@ void BottomInfo::layoutReactionsText() { QSize BottomInfo::countOptimalSize() { auto width = 0; - if (_data.flags & (Data::Flag::OutLayout | Data::Flag::Sending)) { + if (!AyuFeatures::MessageShot::isTakingShot() && _data.flags & (Data::Flag::OutLayout | Data::Flag::Sending)) { width += st::historySendStateSpace; } width += _authorEditedDate.maxWidth(); diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index eb2af43bb..53c2af3bf 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -83,7 +83,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ayu/database/ayu_database.h" #include "ayu/messages/ayu_messages_controller.h" #include "ayu/ui/context_menu/context_menu.h" -#include "ayu/ui/boxes/message_history_box.h" #include "ayu/ui/sections/edited/edited_log_section.h" diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 96c3173bb..c7c4c059c 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -47,6 +47,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "styles/style_chat.h" +// AyuGram includes +#include "ayu/features/messageshot/message_shot.h" + + namespace HistoryView { namespace { @@ -306,6 +310,10 @@ void UnreadBar::paint( int y, int w, bool chatWide) const { + if (AyuFeatures::MessageShot::isTakingShot()) { + return; + } + const auto st = context.st; const auto bottom = y + height(); y += marginTop(); @@ -668,6 +676,10 @@ bool Element::isTopicRootReply() const { } int Element::skipBlockWidth() const { + if (AyuFeatures::MessageShot::ignoreRender(AyuFeatures::MessageShot::RenderPart::Date)) { + return st::msgDateDelta.x(); + } + return st::msgDateSpace + infoWidth() - st::msgDateDelta.x(); } @@ -1177,6 +1189,10 @@ void Element::destroyUnreadBar() { } int Element::displayedDateHeight() const { + if (AyuFeatures::MessageShot::isTakingShot()) { + return 0; + } + if (auto date = Get()) { return date->height(); } diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index e3263e41d..3e0b871a3 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -43,6 +43,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_chat_helpers.h" #include "styles/style_dialogs.h" +// AyuGram includes +#include "ayu/features/messageshot/message_shot.h" + + namespace HistoryView { namespace { @@ -853,10 +857,14 @@ int Message::marginTop() const { } result += displayedDateHeight(); if (const auto bar = Get()) { - result += bar->height(); + if (!AyuFeatures::MessageShot::isTakingShot()) { + result += bar->height(); + } } if (const auto service = Get()) { - result += service->height; + if (!AyuFeatures::MessageShot::isTakingShot()) { + result += service->height; + } } return result; } @@ -910,7 +918,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/); auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop()); - const auto displayInfo = needInfoDisplay(); + const auto displayInfo = needInfoDisplay() && !AyuFeatures::MessageShot::ignoreRender(AyuFeatures::MessageShot::RenderPart::Date); const auto reactionsInBubble = _reactions && embedReactionsInBubble(); auto mediaSelectionIntervals = (!context.selected() && mediaDisplayed) @@ -3359,6 +3367,10 @@ bool Message::displayRightActionComments() const { } std::optional Message::rightActionSize() const { + if (AyuFeatures::MessageShot::isTakingShot()) { + return {}; + } + if (displayRightActionComments()) { const auto views = data()->Get(); Assert(views != nullptr); diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index 017289a0b..e029cf580 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -53,6 +53,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +// AyuGram includes +#include "ayu/features/messageshot/message_shot.h" + + namespace HistoryView { namespace { @@ -143,6 +147,10 @@ PinnedWidget::PinnedWidget( ) | rpl::start_with_next([=] { confirmDeleteSelected(); }, _topBar->lifetime()); + _topBar->messageShotSelectionRequest( + ) | rpl::start_with_next([=] { + AyuFeatures::MessageShot::Wrapper(_inner); + }, _topBar->lifetime()); _topBar->forwardSelectionRequest( ) | rpl::start_with_next([=] { confirmForwardSelected(); diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 157a61977..f3b0d63ef 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -96,6 +96,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +// AyuGram includes +#include "ayu/features/messageshot/message_shot.h" + + namespace HistoryView { namespace { @@ -283,6 +287,10 @@ RepliesWidget::RepliesWidget( ) | rpl::start_with_next([=] { confirmDeleteSelected(); }, _topBar->lifetime()); + _topBar->messageShotSelectionRequest( + ) | rpl::start_with_next([=] { + AyuFeatures::MessageShot::Wrapper(_inner); + }, _topBar->lifetime()); _topBar->forwardSelectionRequest( ) | rpl::start_with_next([=] { confirmForwardSelected(); diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index a086d71cb..bba30f425 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -66,6 +66,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +// AyuGram includes +#include "ayu/features/messageshot/message_shot.h" + + namespace HistoryView { object_ptr ScheduledMemento::createWidget( @@ -136,6 +140,10 @@ ScheduledWidget::ScheduledWidget( ) | rpl::start_with_next([=] { confirmDeleteSelected(); }, _topBar->lifetime()); + _topBar->messageShotSelectionRequest( + ) | rpl::start_with_next([=] { + AyuFeatures::MessageShot::Wrapper(_inner); + }, _topBar->lifetime()); _topBar->clearSelectionRequest( ) | rpl::start_with_next([=] { clearSelected(); diff --git a/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp b/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp index e96738d0d..722e3021a 100644 --- a/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp @@ -31,6 +31,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_chat_helpers.h" #include "styles/style_window.h" +// AyuGram includes +#include "ayu/features/messageshot/message_shot.h" + + namespace HistoryView { namespace { @@ -110,6 +114,10 @@ SublistWidget::SublistWidget( ) | rpl::start_with_next([=] { confirmDeleteSelected(); }, _topBar->lifetime()); + _topBar->messageShotSelectionRequest( + ) | rpl::start_with_next([=] { + AyuFeatures::MessageShot::Wrapper(_inner); + }, _topBar->lifetime()); _topBar->forwardSelectionRequest( ) | rpl::start_with_next([=] { confirmForwardSelected(); diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index 555de8e18..b9e691eb9 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -119,6 +119,7 @@ TopBarWidget::TopBarWidget( , _forward(this, tr::lng_selected_forward(), st::defaultActiveButton) , _sendNow(this, tr::lng_selected_send_now(), st::defaultActiveButton) , _delete(this, tr::lng_selected_delete(), st::defaultActiveButton) +, _messageShot(this, tr::ayu_MessageShotTopBarText(), st::defaultActiveButton) , _back(this, st::historyTopBarBack) , _cancelChoose(this, st::topBarCloseChoose) , _call(this, st::topBarCall) @@ -141,6 +142,8 @@ TopBarWidget::TopBarWidget( _sendNow->setWidthChangedCallback([=] { updateControlsGeometry(); }); _delete->setClickedCallback([=] { _deleteSelection.fire({}); }); _delete->setWidthChangedCallback([=] { updateControlsGeometry(); }); + _messageShot->setClickedCallback([=] { _messageShotSelection.fire({}); }); + _messageShot->setWidthChangedCallback([=] { updateControlsGeometry(); }); _clear->setClickedCallback([=] { _clearSelection.fire({}); }); _call->setClickedCallback([=] { call(); }); _groupCall->setClickedCallback([=] { groupCall(); }); @@ -970,6 +973,7 @@ void TopBarWidget::updateControlsGeometry() { auto buttonsWidth = (_forward->isHidden() ? 0 : _forward->contentWidth()) + (_sendNow->isHidden() ? 0 : _sendNow->contentWidth()) + (_delete->isHidden() ? 0 : _delete->contentWidth()) + + (_messageShot->isHidden() ? 0 : _messageShot->contentWidth()) + _clear->width(); buttonsWidth += buttonsLeft + st::topBarActionSkip * 3; @@ -978,6 +982,7 @@ void TopBarWidget::updateControlsGeometry() { _forward->setFullWidth(buttonFullWidth); _sendNow->setFullWidth(buttonFullWidth); _delete->setFullWidth(buttonFullWidth); + _messageShot->setFullWidth(buttonFullWidth); selectedButtonsTop += (height() - _forward->height()) / 2; @@ -992,6 +997,12 @@ void TopBarWidget::updateControlsGeometry() { } _delete->moveToLeft(buttonsLeft, selectedButtonsTop); + if (!_delete->isHidden()) { + buttonsLeft += _delete->width() + st::topBarActionSkip; + } + + _messageShot->moveToLeft(buttonsLeft, selectedButtonsTop); + _clear->moveToRight(st::topBarActionSkip, selectedButtonsTop); if (!_cancelChoose->isHidden()) { @@ -1091,6 +1102,7 @@ void TopBarWidget::updateControlsVisibility() { } _clear->show(); _delete->setVisible(_canDelete); + _messageShot->setVisible(true); _forward->setVisible(_canForward); _sendNow->setVisible(_canSendNow); @@ -1266,10 +1278,12 @@ void TopBarWidget::showSelected(SelectedState state) { _forward->setNumbersText(_selectedCount); _sendNow->setNumbersText(_selectedCount); _delete->setNumbersText(_selectedCount); + _messageShot->setNumbersText(_selectedCount); if (!wasSelectedState) { _forward->finishNumbersAnimation(); _sendNow->finishNumbersAnimation(); _delete->finishNumbersAnimation(); + _messageShot->finishNumbersAnimation(); } } if (visibilityChanged) { diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h index 36d18a5f6..d4cb8b2d6 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h @@ -100,6 +100,9 @@ public: [[nodiscard]] rpl::producer<> deleteSelectionRequest() const { return _deleteSelection.events(); } + [[nodiscard]] rpl::producer<> messageShotSelectionRequest() const { + return _messageShotSelection.events(); + } [[nodiscard]] rpl::producer<> clearSelectionRequest() const { return _clearSelection.events(); } @@ -206,7 +209,7 @@ private: Ui::Animations::Simple _searchShown; object_ptr _clear; - object_ptr _forward, _sendNow, _delete; + object_ptr _forward, _sendNow, _delete, _messageShot; object_ptr _searchField = { nullptr }; object_ptr> _chooseFromUser = { nullptr }; @@ -252,6 +255,7 @@ private: rpl::event_stream<> _forwardSelection; rpl::event_stream<> _sendNowSelection; rpl::event_stream<> _deleteSelection; + rpl::event_stream<> _messageShotSelection; rpl::event_stream<> _clearSelection; rpl::event_stream<> _cancelChooseForReport; diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index f89a5771a..b4a141a37 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -56,6 +56,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +// AyuGram includes +#include "ayu/features/messageshot/message_shot.h" + + namespace HistoryView { namespace { @@ -697,7 +701,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const { } p.setOpacity(1.); } - if (displayMute) { + if (displayMute && !AyuFeatures::MessageShot::isTakingShot()) { auto muteRect = style::rtlrect(rthumb.x() + (rthumb.width() - st::historyVideoMessageMuteSize) / 2, rthumb.y() + st::msgDateImgDelta, st::historyVideoMessageMuteSize, st::historyVideoMessageMuteSize, width()); p.setPen(Qt::NoPen); p.setBrush(sti->msgDateImgBg); @@ -714,7 +718,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const { drawCornerStatus(p, context, QPoint()); } } else if (!skipDrawingSurrounding) { - if (isRound) { + if (isRound && !AyuFeatures::MessageShot::ignoreRender(AyuFeatures::MessageShot::RenderPart::Date)) { const auto mediaUnread = item->hasUnreadMediaFlag(); auto statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x(); auto statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y(); @@ -820,7 +824,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const { .selection = context.selection, .highlight = highlightRequest ? &*highlightRequest : nullptr, }); - } else if (!inWebPage && !skipDrawingSurrounding) { + } else if (!inWebPage && !skipDrawingSurrounding && !AyuFeatures::MessageShot::ignoreRender(AyuFeatures::MessageShot::RenderPart::Date)) { auto fullRight = paintx + usex + usew; auto fullBottom = painty + painth; auto maxRight = _parent->width() - st::msgMargin.left(); @@ -1023,7 +1027,7 @@ void Gif::drawCornerStatus( const auto padding = st::msgDateImgPadding; const auto radial = _animation && _animation->radial.animating(); const auto cornerDownload = downloadInCorner() && !dataLoaded() && !_data->loadedInMediaCache(); - const auto cornerMute = _streamed && _data->isVideoFile() && !cornerDownload; + const auto cornerMute = _streamed && _data->isVideoFile() && !cornerDownload && !AyuFeatures::MessageShot::isTakingShot(); const auto addLeft = cornerDownload ? (st::historyVideoDownloadSize + 2 * padding.y()) : 0; const auto addRight = cornerMute ? st::historyVideoMuteSize : 0; const auto downloadWidth = cornerDownload ? st::normalFont->width(_downloadSize) : 0; @@ -2056,11 +2060,20 @@ bool Gif::needInfoDisplay() const { } bool Gif::needCornerStatusDisplay() const { + if (AyuFeatures::MessageShot::ignoreRender(AyuFeatures::MessageShot::RenderPart::Date)) { + return false; + } + return _data->isVideoFile() || needInfoDisplay(); } void Gif::ensureTranscribeButton() const { + if (AyuFeatures::MessageShot::isTakingShot()) { + _transcribe = nullptr; + return; + } + if (_data->isVideoMessage() && !_parent->data()->media()->ttlSeconds() && (_data->session().premium() diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index fa633ab37..aa02b7925 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -39,6 +39,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/application.h" #include "styles/style_chat.h" +// AyuGran includes +#include "ayu/features/messageshot/message_shot.h" + + namespace HistoryView { namespace { @@ -902,6 +906,10 @@ bool Photo::dataLoaded() const { } bool Photo::needInfoDisplay() const { + if (AyuFeatures::MessageShot::ignoreRender(AyuFeatures::MessageShot::RenderPart::Date)) { + return false; + } + if (_parent->data()->isFakeBotAbout()) { return false; } diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp index 39ae8087a..bcf062dd5 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp @@ -28,6 +28,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_chat.h" #include "styles/style_chat_helpers.h" +// AyuGram includes +#include "ayu/features/messageshot/message_shot.h" + + namespace HistoryView::Reactions { namespace { @@ -484,7 +488,7 @@ void InlineList::paint( p.setOpacity(1.); } } - if (!animations.empty()) { + if (!animations.empty() && !AyuFeatures::MessageShot::isTakingShot()) { // fix crash when taking shot const auto now = context.now; context.reactionInfo->effectPaint = [ now, diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp index 3da8d85db..7efef0d37 100644 --- a/Telegram/SourceFiles/settings/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/settings_chat.cpp @@ -72,6 +72,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_menu_icons.h" #include "styles/style_window.h" +// AyuGram includes +#include "ayu/ui/settings/settings_ayu.h" +#include "ayu/features/messageshot/message_shot.h" +#include "window/themes/window_theme_preview.h" + + namespace Settings { namespace { @@ -247,7 +253,7 @@ void ColorsPalette::show(Type type) { return; } list.insert(list.begin(), scheme->accentColor); - const auto color = Core::App().settings().themesAccentColors().get(type); + const auto color = AyuFeatures::MessageShot::isChoosingTheme() ? AyuFeatures::MessageShot::getSelectedColorFromDefault() : Core::App().settings().themesAccentColors().get(type); const auto current = color.value_or(scheme->accentColor); const auto i = ranges::find(list, current); if (i == end(list)) { @@ -1290,7 +1296,19 @@ void SetupDefaultThemes( container.get(), container.get()); + const auto updateMessageShotPalette = [=](const QString &path) + { + const Data::CloudTheme theme; + if (const auto preview = PreviewFromFile(QByteArray(), path, theme)) { + AyuFeatures::MessageShot::setPalette(preview->instance.palette); + } + }; + const auto chosen = [] { + if (AyuFeatures::MessageShot::isChoosingTheme()) { + return AyuFeatures::MessageShot::getSelectedFromDefault(); + } + const auto &object = Background()->themeObject(); if (object.cloud.id) { return Type(-1); @@ -1328,6 +1346,12 @@ void SetupDefaultThemes( const auto schemeClicked = [=]( const Scheme &scheme, Qt::KeyboardModifiers modifiers) { + if (AyuFeatures::MessageShot::isChoosingTheme()) { + AyuFeatures::MessageShot::setDefaultSelected(scheme.type); + updateMessageShotPalette(scheme.path); + return; + } + apply(scheme); }; @@ -1371,6 +1395,16 @@ void SetupDefaultThemes( return; } if (i != end(checks)) { + if (AyuFeatures::MessageShot::isChoosingTheme()) { + if (const auto color = AyuFeatures::MessageShot::getSelectedColorFromDefault()) { + const auto colorizer = ColorizerFrom(*scheme, color.value()); + i->second->setColors(ColorsFromScheme(*scheme, colorizer)); + } else { + i->second->setColors(ColorsFromScheme(*scheme)); + } + return; + } + if (const auto color = colors.get(type)) { const auto colorizer = ColorizerFrom(*scheme, *color); i->second->setColors(ColorsFromScheme(*scheme, colorizer)); @@ -1380,6 +1414,21 @@ void SetupDefaultThemes( } }; group->setChangedCallback([=](Type type) { + if (AyuFeatures::MessageShot::isChoosingTheme()) { + palette->show(type); + refreshColorizer(type); + group->setValue(type); + AyuFeatures::MessageShot::setDefaultSelected(type); + + const auto scheme = ranges::find(kSchemesList, type, &Scheme::type); + if (scheme == end(kSchemesList)) { + return; + } + + updateMessageShotPalette(scheme->path); + return; + } + group->setValue(chosen()); }); for (const auto &scheme : kSchemesList) { @@ -1430,8 +1479,32 @@ void SetupDefaultThemes( } }, block->lifetime()); + if (AyuFeatures::MessageShot::isChoosingTheme()) { + palette->selected() | rpl::start_with_next([=](QColor color) { + AyuFeatures::MessageShot::setDefaultSelectedColor(color); + refreshColorizer(AyuFeatures::MessageShot::getSelectedFromDefault()); + + const auto type = chosen(); + const auto scheme = ranges::find(kSchemesList, type, &Scheme::type); + if (scheme == end(kSchemesList)) { + return; + } + + updateMessageShotPalette(scheme->path); + }, container->lifetime()); + + AyuFeatures::MessageShot::resetDefaultSelectedEvents() | rpl::start_with_next([=] { + refreshColorizer(AyuFeatures::MessageShot::getSelectedFromDefault()); // hide colorizer + group->setValue(Type(-1)); + }, container->lifetime()); + } + palette->selected( ) | rpl::start_with_next([=](QColor color) { + if (AyuFeatures::MessageShot::isChoosingTheme()) { + return; + } + if (Background()->editingTheme()) { // We don't remember old accent color to revert it properly // in Window::Theme::Revert which is called by Editor. diff --git a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp index 1e71863af..2f26dc348 100644 --- a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp +++ b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp @@ -35,6 +35,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include +// AyuGram includes +#include "ayu/features/messageshot/message_shot.h" + + namespace Window { namespace Theme { namespace { @@ -332,11 +336,21 @@ rpl::producer CloudList::allShown() const { void CloudList::setup() { _group->setChangedCallback([=](int selected) { + if (AyuFeatures::MessageShot::isChoosingTheme()) { + return; + } + const auto &object = Background()->themeObject(); _group->setValue(groupValueForId( object.cloud.id ? object.cloud.id : kFakeCloudThemeId)); }); + if (AyuFeatures::MessageShot::isChoosingTheme()) { + AyuFeatures::MessageShot::resetCustomSelectedEvents() | rpl::start_with_next([=] { + _group->setValue(-1); + }, _outer->lifetime()); + } + auto cloudListChanges = rpl::single(rpl::empty) | rpl::then( _window->session().data().cloudThemes().updated() ); @@ -436,6 +450,13 @@ bool CloudList::applyChangesFrom(std::vector &&list) { changed = true; } _group->setValue(groupValueForId(id)); + + if (AyuFeatures::MessageShot::isChoosingTheme()) { + if (const auto selected = AyuFeatures::MessageShot::getSelectedFromCustom()) { + _group->setValue(groupValueForId(selected.value().id)); + } + } + return changed; } @@ -521,6 +542,14 @@ void CloudList::insert(int index, const Data::CloudTheme &theme) { return; } const auto &cloud = i->theme; + + if (AyuFeatures::MessageShot::isChoosingTheme()) { + AyuFeatures::MessageShot::setTheme(cloud); + AyuFeatures::MessageShot::setCustomSelected(cloud); + _group->setValue(groupValueForId(cloud.id)); + return; + } + if (button == Qt::RightButton) { showMenu(*i); } else if (cloud.documentId) { diff --git a/Telegram/SourceFiles/window/themes/window_themes_embedded.cpp b/Telegram/SourceFiles/window/themes/window_themes_embedded.cpp index 541534662..3a3c20b84 100644 --- a/Telegram/SourceFiles/window/themes/window_themes_embedded.cpp +++ b/Telegram/SourceFiles/window/themes/window_themes_embedded.cpp @@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/core_settings.h" #include "ui/style/style_palette_colorizer.h" +// AyuGram includes +#include "ayu/features/messageshot/message_shot.h" + + namespace Window { namespace Theme { namespace { @@ -188,7 +192,7 @@ style::colorizer ColorizerForTheme(const QString &absolutePath) { return {}; } const auto &colors = Core::App().settings().themesAccentColors(); - if (const auto accent = colors.get(i->type)) { + if (const auto accent = AyuFeatures::MessageShot::isChoosingTheme() ? AyuFeatures::MessageShot::getSelectedColorFromDefault() : colors.get(i->type)) { return ColorizerFrom(*i, *accent); } return {}; diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp index 55370d92e..5d4c20300 100644 --- a/Telegram/SourceFiles/window/window_main_menu.cpp +++ b/Telegram/SourceFiles/window/window_main_menu.cpp @@ -75,7 +75,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL // AyuGram includes #include "ayu/ayu_settings.h" #include "ayu/utils/telegram_helpers.h" -#include "ayu/ui/boxes/confirmation_box.h" +#include "ayu/ui/boxes/server_read_confirmation_box.h" #include "boxes/abstract_box.h" #include "ayu/features/streamer_mode/streamer_mode.h" #include "styles/style_ayu_icons.h"