/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "boxes/create_poll_box.h" #include "poll/poll_media_upload.h" #include "base/call_delayed.h" #include "base/qt/qt_key_modifiers.h" #include "base/unixtime.h" #include "boxes/premium_limits_box.h" #include "base/event_filter.h" #include "base/random.h" #include "base/unique_qptr.h" #include "chat_helpers/emoji_suggestions_widget.h" #include "chat_helpers/message_field.h" #include "chat_helpers/tabbed_panel.h" #include "chat_helpers/tabbed_selector.h" #include "core/file_utilities.h" #include "core/mime_type.h" #include "core/application.h" #include "core/core_settings.h" #include "core/shortcuts.h" #include "core/ui_integration.h" #include "ui/power_saving.h" #include "data/data_cloud_file.h" #include "data/data_document.h" #include "data/data_file_origin.h" #include "data/data_location.h" #include "data/data_poll.h" #include "data/data_peer.h" #include "data/data_photo.h" #include "data/data_session.h" #include "data/data_user.h" #include "data/stickers/data_custom_emoji.h" #include "history/view/media/menu/history_view_poll_menu.h" #include "history/view/history_view_schedule_box.h" #include "lang/lang_keys.h" #include "layout/layout_document_generic_preview.h" #include "main/main_app_config.h" #include "mainwidget.h" #include "mainwindow.h" #include "platform/platform_file_utilities.h" #include "main/main_session.h" #include "menu/menu_send.h" #include "settings/detailed_settings_button.h" #include "settings/settings_common.h" #include "storage/file_upload.h" #include "storage/localimageloader.h" #include "storage/storage_account.h" #include "storage/storage_media_prepare.h" #include "ui/controls/emoji_button.h" #include "ui/controls/emoji_button_factory.h" #include "ui/controls/location_picker.h" #include "ui/chat/attach/attach_prepare.h" #include "ui/dynamic_image.h" #include "ui/dynamic_thumbnails.h" #include "ui/effects/radial_animation.h" #include "ui/effects/ripple_animation.h" #include "ui/effects/ttl_icon.h" #include "ui/painter.h" #include "ui/rect.h" #include "ui/text/text_utilities.h" #include "ui/toast/toast.h" #include "ui/vertical_list.h" #include "ui/widgets/buttons.h" #include "ui/widgets/dropdown_menu.h" #include "ui/widgets/menu/menu_action.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/fields/input_field.h" #include "ui/widgets/labels.h" #include "ui/boxes/choose_date_time.h" #include "ui/text/format_values.h" #include "ui/widgets/popup_menu.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" #include "ui/wrap/fade_wrap.h" #include "ui/wrap/slide_wrap.h" #include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout_reorder.h" #include "ui/ui_utility.h" #include "window/section_widget.h" #include "window/window_session_controller.h" #include "apiwrap.h" #include "styles/style_boxes.h" #include "styles/style_dialogs.h" #include "styles/style_chat.h" #include "styles/style_chat_helpers.h" // defaultComposeFiles. #include "styles/style_layers.h" #include "styles/style_menu_icons.h" #include "styles/style_overview.h" #include "styles/style_polls.h" #include "styles/style_settings.h" #include #include namespace { constexpr auto kQuestionLimit = 255; constexpr auto kMaxOptionsCount = PollData::kMaxOptions; constexpr auto kOptionLimit = 100; constexpr auto kWarnQuestionLimit = 80; constexpr auto kWarnOptionLimit = 30; constexpr auto kSolutionLimit = 200; constexpr auto kWarnSolutionLimit = 60; constexpr auto kErrorLimit = 99; constexpr auto kMediaUploadMaxAge = 45 * 60 * crl::time(1000); using PollMediaState = PollMediaUpload::PollMediaState; using PollMediaButton = PollMediaUpload::PollMediaButton; using PollMediaUploader = PollMediaUpload::PollMediaUploader; using PollMediaUpload::FileListFromMimeData; using PollMediaUpload::GenerateDocumentFilePreview; using PollMediaUpload::LocalImageThumbnail; using PollMediaUpload::PreparePollMediaTask; using PollMediaUpload::UploadContext; using PollMediaUpload::ValidateFileDragData; class Options { public: using AttachCallback = Fn, std::shared_ptr)>; using FieldDropCallback = Fn, std::shared_ptr)>; using WidgetDropCallback = Fn, std::shared_ptr)>; Options( not_null box, not_null container, not_null controller, ChatHelpers::TabbedPanel *emojiPanel, bool chooseCorrectEnabled, AttachCallback attachCallback, FieldDropCallback fieldDropCallback, WidgetDropCallback widgetDropCallback); [[nodiscard]] bool hasOptions() const; [[nodiscard]] bool isValid() const; [[nodiscard]] bool hasCorrect() const; [[nodiscard]] bool hasUploadingMedia() const; bool refreshStaleMedia(crl::time threshold); [[nodiscard]] std::vector toPollAnswers() const; void focusFirst(); void enableChooseCorrect(bool enabled, bool multiCorrect = false); [[nodiscard]] not_null layoutWidget() const; [[nodiscard]] rpl::producer usedCount() const; [[nodiscard]] rpl::producer> scrollToWidget() const; [[nodiscard]] rpl::producer<> backspaceInFront() const; [[nodiscard]] rpl::producer<> tabbed() const; private: class Option { public: Option( not_null outer, not_null container, not_null session, int position, std::shared_ptr group, AttachCallback attachCallback, FieldDropCallback fieldDropCallback, WidgetDropCallback widgetDropCallback); Option(const Option &other) = delete; Option &operator=(const Option &other) = delete; void enableChooseCorrect( std::shared_ptr group, bool multiCorrect = false, Fn checkboxChanged = nullptr); void show(anim::type animated); void destroy(FnMut done); [[nodiscard]] bool hasShadow() const; void createShadow(); void destroyShadow(); [[nodiscard]] bool isEmpty() const; [[nodiscard]] bool isGood() const; [[nodiscard]] bool isTooLong() const; [[nodiscard]] bool isCorrect() const; [[nodiscard]] bool uploadingMedia() const; bool refreshMediaIfStale(crl::time threshold); [[nodiscard]] bool hasFocus() const; void setFocus() const; void setPlaceholder() const; void removePlaceholder() const; void showAddIcon(bool show); [[nodiscard]] not_null field() const; [[nodiscard]] PollAnswer toPollAnswer(int index) const; [[nodiscard]] Ui::RpWidget *handleWidget() const; private: void createAttach(); void createWarning(); void createHandle(); void updateFieldGeometry(); base::unique_qptr> _wrap; not_null _content; base::unique_qptr> _correct; base::unique_qptr> _handle; bool _hasCorrect = false; Ui::InputField *_field = nullptr; base::unique_qptr _shadow; base::unique_qptr _attach; AttachCallback _attachCallback; FieldDropCallback _fieldDropCallback; WidgetDropCallback _widgetDropCallback; std::shared_ptr _media; Ui::FadeWrapScaled *_addIcon = nullptr; }; [[nodiscard]] bool full() const; [[nodiscard]] bool correctShadows() const; void fixShadows(); void removeEmptyTail(); void addEmptyOption(); void checkLastOption(); void validateState(); void fixAfterErase(); void destroy(std::unique_ptr