diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 196b30b24..1e60d6eea 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1744,6 +1744,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_export_option_location" = "Download path: {path}"; "lng_export_option_html" = "Human-readable HTML"; "lng_export_option_json" = "Machine-readable JSON"; +"lng_export_limits" = "From: {from}, Till: {till}"; +"lng_export_beginning" = "Beginning"; +"lng_export_end" = "End"; +"lng_export_from_beginning" = "From Beginning"; +"lng_export_till_end" = "Till End"; "lng_export_start" = "Export"; "lng_export_state_initializing" = "Initializing..."; "lng_export_state_userpics" = "Profile pictures"; diff --git a/Telegram/SourceFiles/boxes/calendar_box.cpp b/Telegram/SourceFiles/boxes/calendar_box.cpp index 1cdc46dee..8c6c3d292 100644 --- a/Telegram/SourceFiles/boxes/calendar_box.cpp +++ b/Telegram/SourceFiles/boxes/calendar_box.cpp @@ -440,13 +440,19 @@ void CalendarBox::Title::paintEvent(QPaintEvent *e) { p.drawTextLeft((width() - _textWidth) / 2, (height() - st::calendarTitleFont->height) / 2, width(), _text, _textWidth); } -CalendarBox::CalendarBox(QWidget*, QDate month, QDate highlighted, Fn callback) +CalendarBox::CalendarBox( + QWidget*, + QDate month, + QDate highlighted, + Fn callback, + FnMut)> finalize) : _context(std::make_unique(month, highlighted)) , _inner(this, _context.get()) , _title(this, _context.get()) , _previous(this, st::calendarPrevious) , _next(this, st::calendarNext) -, _callback(std::move(callback)) { +, _callback(std::move(callback)) +, _finalize(std::move(finalize)) { } void CalendarBox::setMinDate(QDate date) { @@ -477,6 +483,10 @@ void CalendarBox::prepare() { subscribe(_context->month(), [this](QDate month) { monthChanged(month); }); _context->start(); + + if (_finalize) { + _finalize(this); + } } bool CalendarBox::isPreviousEnabled() const { diff --git a/Telegram/SourceFiles/boxes/calendar_box.h b/Telegram/SourceFiles/boxes/calendar_box.h index 867fb7677..e2385bcd9 100644 --- a/Telegram/SourceFiles/boxes/calendar_box.h +++ b/Telegram/SourceFiles/boxes/calendar_box.h @@ -15,7 +15,12 @@ class IconButton; class CalendarBox : public BoxContent { public: - CalendarBox(QWidget*, QDate month, QDate highlighted, Fn callback); + CalendarBox( + QWidget*, + QDate month, + QDate highlighted, + Fn callback, + FnMut)> finalize = nullptr); void setMinDate(QDate date); void setMaxDate(QDate date); @@ -45,5 +50,6 @@ private: object_ptr _next; Fn _callback; + FnMut)> _finalize; }; diff --git a/Telegram/SourceFiles/export/export_settings.cpp b/Telegram/SourceFiles/export/export_settings.cpp index d44e17fcb..8c3ae84d0 100644 --- a/Telegram/SourceFiles/export/export_settings.cpp +++ b/Telegram/SourceFiles/export/export_settings.cpp @@ -41,6 +41,8 @@ bool Settings::validate() const { return false; } else if (!media.validate()) { return false; + } else if (singlePeerTill > 0 && singlePeerTill <= singlePeerFrom) { + return false; } return true; }; diff --git a/Telegram/SourceFiles/export/export_settings.h b/Telegram/SourceFiles/export/export_settings.h index 8e4f4cdc6..39bbebf9a 100644 --- a/Telegram/SourceFiles/export/export_settings.h +++ b/Telegram/SourceFiles/export/export_settings.h @@ -78,6 +78,8 @@ struct Settings { MediaSettings media; MTPInputPeer singlePeer = MTP_inputPeerEmpty(); + TimeId singlePeerFrom = 0; + TimeId singlePeerTill = 0; TimeId availableAt = 0; diff --git a/Telegram/SourceFiles/export/view/export.style b/Telegram/SourceFiles/export/view/export.style index 33c5985c5..463bb5a98 100644 --- a/Telegram/SourceFiles/export/view/export.style +++ b/Telegram/SourceFiles/export/view/export.style @@ -34,6 +34,7 @@ exportLocationLabel: FlatLabel(boxLabel) { maxHeight: 21px; } exportLocationPadding: margins(22px, 8px, 22px, 8px); +exportLimitsPadding: margins(22px, 0px, 22px, 0px); exportAboutOptionLabel: FlatLabel(defaultFlatLabel) { textFg: windowSubTextFg; diff --git a/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp b/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp index 0eb212278..be010aabe 100644 --- a/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp +++ b/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp @@ -158,6 +158,12 @@ void PanelController::showSettings() { auto settings = base::make_unique_q( _panel, *_settings); + settings->setShowBoxCallback([=](object_ptr box) { + _panel->showBox( + std::move(box), + LayerOption::KeepOther, + anim::type::normal); + }); settings->startClicks( ) | rpl::start_with_next([=]() { diff --git a/Telegram/SourceFiles/export/view/export_view_settings.cpp b/Telegram/SourceFiles/export/view/export_view_settings.cpp index a14a82020..85b9765df 100644 --- a/Telegram/SourceFiles/export/view/export_view_settings.cpp +++ b/Telegram/SourceFiles/export/view/export_view_settings.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/wrap/fade_wrap.h" #include "platform/platform_specific.h" #include "core/file_utilities.h" +#include "boxes/calendar_box.h" #include "auth_session.h" #include "styles/style_widgets.h" #include "styles/style_export.h" @@ -210,6 +211,7 @@ void SettingsWidget::setupPathAndFormat( not_null container) { if (_singlePeerId != 0) { addLocationLabel(container); + addLimitsLabel(container); return; } const auto formatGroup = std::make_shared>( @@ -271,6 +273,126 @@ void SettingsWidget::addLocationLabel( #endif // OS_MAC_STORE } +void SettingsWidget::addLimitsLabel( + not_null container) { + auto pathLabel = value() | rpl::map([](const Settings &data) { + return std::make_tuple(data.singlePeerFrom, data.singlePeerTill); + }) | rpl::distinct_until_changed( + ) | rpl::map([](TimeId from, TimeId till) { + const auto begin = from + ? langDayOfMonthFull(ParseDateTime(from).date()) + : lang(lng_export_beginning); + const auto end = till + ? langDayOfMonthFull(ParseDateTime(till).date()) + : lang(lng_export_end); + auto fromLink = TextWithEntities{ begin }; + fromLink.entities.push_back(EntityInText( + EntityInTextCustomUrl, + 0, + begin.size(), + QString("internal:edit_from"))); + auto tillLink = TextWithEntities{ end }; + tillLink.entities.push_back(EntityInText( + EntityInTextCustomUrl, + 0, + end.size(), + QString("internal:edit_till"))); + return lng_export_limits__generic( + lt_from, + fromLink, + lt_till, + tillLink); + }) | rpl::after_next([=] { + container->resizeToWidth(container->width()); + }); + const auto label = container->add( + object_ptr( + container, + std::move(pathLabel), + st::exportLocationLabel), + st::exportLimitsPadding); + label->setClickHandlerFilter([=]( + const ClickHandlerPtr &handler, + Qt::MouseButton) { + const auto url = handler->dragText(); + if (url == qstr("internal:edit_from")) { + const auto done = [=](TimeId limit) { + changeData([&](Settings &settings) { + settings.singlePeerFrom = limit; + }); + }; + editDateLimit( + readData().singlePeerFrom, + 0, + readData().singlePeerTill, + lng_export_from_beginning, + done); + } else if (url == qstr("internal:edit_till")) { + const auto done = [=](TimeId limit) { + changeData([&](Settings &settings) { + settings.singlePeerTill = limit; + }); + }; + editDateLimit( + readData().singlePeerTill, + readData().singlePeerFrom, + 0, + lng_export_till_end, + done); + } else { + Unexpected("Click handler URL in export limits edit."); + } + return false; + }); + +} + +void SettingsWidget::editDateLimit( + TimeId current, + TimeId min, + TimeId max, + LangKey resetLabel, + Fn done) { + Expects(_showBoxCallback != nullptr); + + const auto highlighted = current + ? ParseDateTime(current).date() + : max + ? ParseDateTime(max).date() + : min + ? ParseDateTime(min).date() + : QDate::currentDate(); + const auto month = highlighted; + const auto shared = std::make_shared>(); + const auto finalize = [=](not_null box) { + box->setMaxDate(max + ? ParseDateTime(max).date() + : QDate::currentDate()); + box->setMinDate(min + ? ParseDateTime(min).date() + : QDate(2013, 8, 1)); // Telegram was launched in August 2013 :) + box->addLeftButton(langFactory(resetLabel), crl::guard(this, [=] { + done(0); + if (const auto weak = shared->data()) { + weak->closeBox(); + } + })); + }; + const auto callback = crl::guard(this, [=](const QDate &date) { + done(ServerTimeFromParsed(QDateTime(date))); + if (const auto weak = shared->data()) { + weak->closeBox(); + } + }); + auto box = Box( + month, + highlighted, + callback, + finalize); + *shared = make_weak(box.data()); + _showBoxCallback(std::move(box)); +} + not_null SettingsWidget::setupButtons( not_null scroll, not_null wrap) { diff --git a/Telegram/SourceFiles/export/view/export_view_settings.h b/Telegram/SourceFiles/export/view/export_view_settings.h index 193cd9689..da68694a6 100644 --- a/Telegram/SourceFiles/export/view/export_view_settings.h +++ b/Telegram/SourceFiles/export/view/export_view_settings.h @@ -30,6 +30,10 @@ public: rpl::producer<> startClicks() const; rpl::producer<> cancelClicks() const; + void setShowBoxCallback(Fn)> callback) { + _showBoxCallback = std::move(callback); + } + private: using Type = Settings::Type; using Types = Settings::Types; @@ -70,16 +74,26 @@ private: void addSizeSlider(not_null container); void addLocationLabel( not_null container); + void addLimitsLabel( + not_null container); void chooseFolder(); void refreshButtons( not_null container, bool canStart); + void editDateLimit( + TimeId current, + TimeId min, + TimeId max, + LangKey resetLabel, + Fn done); + const Settings &readData() const; template void changeData(Callback &&callback); PeerId _singlePeerId = 0; + Fn)> _showBoxCallback; // Use through readData / changeData wrappers. Settings _internal_data; diff --git a/Telegram/SourceFiles/rpl/after_next.h b/Telegram/SourceFiles/rpl/after_next.h index 80764b5df..12d20ed90 100644 --- a/Telegram/SourceFiles/rpl/after_next.h +++ b/Telegram/SourceFiles/rpl/after_next.h @@ -30,7 +30,8 @@ public: [method = std::move(method), consumer](auto &&value) { auto copy = method; consumer.put_next_copy(value); - std::move(copy)( + details::callable_invoke( + std::move(copy), std::forward(value)); }, [consumer](auto &&error) { consumer.put_error_forward( diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index b07ba5630..e0a3ad254 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -4345,6 +4345,8 @@ void WriteExportSettings(const Export::Settings &settings) { }, [&](const MTPDinputPeerEmpty &) { data.stream << kSinglePeerTypeEmpty; }); + data.stream << qint32(settings.singlePeerFrom); + data.stream << qint32(settings.singlePeerTill); FileWriteDescriptor file(_exportSettingsKey); file.writeEncrypted(data); @@ -4366,6 +4368,7 @@ Export::Settings ReadExportSettings() { QString path; qint32 singlePeerType = 0, singlePeerBareId = 0; quint64 singlePeerAccessHash = 0; + qint32 singlePeerFrom = 0, singlePeerTill = 0; file.stream >> types >> fullChats @@ -4387,6 +4390,9 @@ Export::Settings ReadExportSettings() { default: return Export::Settings(); } } + if (!file.stream.atEnd()) { + file.stream >> singlePeerFrom >> singlePeerTill; + } auto result = Export::Settings(); result.types = Export::Settings::Types::from_raw(types); result.fullChats = Export::Settings::Types::from_raw(fullChats); @@ -4414,6 +4420,8 @@ Export::Settings ReadExportSettings() { } Unexpected("Type in export data single peer."); }(); + result.singlePeerFrom = singlePeerFrom; + result.singlePeerTill = singlePeerTill; return (file.stream.status() == QDataStream::Ok && result.validate()) ? result : Export::Settings();