From afab21372b27436a25c04a4130a00c6cd89e68ac Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 27 Aug 2016 11:52:05 -0600 Subject: [PATCH] Auto update and codes ("loadlang" etc) supported in the new Settings. --- Telegram/SourceFiles/core/lambda_wrap.h | 2 +- Telegram/SourceFiles/facades.cpp | 5 + Telegram/SourceFiles/facades.h | 4 +- Telegram/SourceFiles/settings/settings.style | 2 + .../settings/settings_general_widget.cpp | 150 +++++++++++++++++- .../settings/settings_general_widget.h | 54 ++++++- .../settings/settings_privacy_widget.cpp | 3 +- .../settings/settings_privacy_widget.h | 9 ++ .../SourceFiles/settings/settings_widget.cpp | 91 +++++++++++ .../SourceFiles/settings/settings_widget.h | 1 + Telegram/SourceFiles/ui/twidget.cpp | 11 +- .../ui/widgets/widget_slide_wrap.h | 3 +- 12 files changed, 318 insertions(+), 17 deletions(-) diff --git a/Telegram/SourceFiles/core/lambda_wrap.h b/Telegram/SourceFiles/core/lambda_wrap.h index 5a93152c04..c66cfd0e2b 100644 --- a/Telegram/SourceFiles/core/lambda_wrap.h +++ b/Telegram/SourceFiles/core/lambda_wrap.h @@ -326,7 +326,7 @@ public: } lambda_wrap &operator=(const lambda_wrap &other) { auto temp = other; - other.swap(*this); + temp.swap(*this); return *this; } diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 235bb231b5..5673890580 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -650,6 +650,9 @@ struct Data { bool TryIPv6 = (cPlatform() == dbipWindows) ? false : true; ProxyData ConnectionProxy; base::Observable ConnectionTypeChanged; + + base::Observable ChooseCustomLang; + }; } // namespace internal @@ -752,4 +755,6 @@ DefineVar(Global, bool, TryIPv6); DefineVar(Global, ProxyData, ConnectionProxy); DefineRefVar(Global, base::Observable, ConnectionTypeChanged); +DefineRefVar(Global, base::Observable, ChooseCustomLang); + } // namespace Global diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index d398736f1f..217389402a 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -316,6 +316,8 @@ DeclareVar(bool, TryIPv6); DeclareVar(ProxyData, ConnectionProxy); DeclareRefVar(base::Observable, ConnectionTypeChanged); +DeclareRefVar(base::Observable, ChooseCustomLang); + } // namespace Global namespace Adaptive { @@ -339,7 +341,7 @@ inline bool Wide() { namespace DebugLogging { inline bool FileLoader() { - return (Global::DebugLoggingFlags() | FileLoaderFlag) != 0; + return (Global::DebugLoggingFlags() & FileLoaderFlag) != 0; } } // namespace DebugLogging diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index 5a27c09843..90178514f4 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -136,3 +136,5 @@ settingsSliderLabelFg: #1485c2; settingsSliderDuration: 200; settingsBackgroundSize: 120px; + +settingsUpdateFg: #999999; diff --git a/Telegram/SourceFiles/settings/settings_general_widget.cpp b/Telegram/SourceFiles/settings/settings_general_widget.cpp index 0059472de3..5b799e72c2 100644 --- a/Telegram/SourceFiles/settings/settings_general_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_general_widget.cpp @@ -29,10 +29,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localstorage.h" #include "pspecific.h" #include "mainwindow.h" +#include "application.h" #include "boxes/languagebox.h" #include "boxes/confirmbox.h" #include "ui/filedialog.h" #include "langloaderplain.h" +#include "autoupdater.h" namespace Settings { namespace { @@ -50,9 +52,125 @@ QString currentVersion() { } // namespace +#ifndef TDESKTOP_DISABLE_AUTOUPDATE +UpdateStateRow::UpdateStateRow(QWidget *parent) : TWidget(parent) +, _check(this, lang(lng_settings_check_now)) +, _restart(this, lang(lng_settings_update_now)) { + connect(_check, SIGNAL(clicked()), this, SLOT(onCheck())); + connect(_restart, SIGNAL(clicked()), this, SIGNAL(restart())); + + Sandbox::connect(SIGNAL(updateChecking()), this, SLOT(onChecking())); + Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onLatest())); + Sandbox::connect(SIGNAL(updateProgress(qint64, qint64)), this, SLOT(onDownloading(qint64, qint64))); + Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onFailed())); + Sandbox::connect(SIGNAL(updateReady()), this, SLOT(onReady())); + + switch (Sandbox::updatingState()) { + case Application::UpdatingDownload: + setState(State::Download, true); + setDownloadProgress(Sandbox::updatingReady(), Sandbox::updatingSize()); + break; + case Application::UpdatingReady: setState(State::Ready, true); break; + default: setState(State::None, true); break; + } +} + +int UpdateStateRow::resizeGetHeight(int newWidth) { + auto labelWidth = [](const QString &label) { + return st::linkFont->width(label) + st::linkFont->spacew; + }; + auto checkLeft = (_state == State::Latest) ? labelWidth(lang(lng_settings_latest_installed)) : 0; + auto restartLeft = labelWidth(lang(lng_settings_update_ready)); + + _check->resizeToWidth(qMin(newWidth, _check->naturalWidth())); + _check->moveToLeft(checkLeft, 0); + + _restart->resizeToWidth(qMin(newWidth, _restart->naturalWidth())); + _restart->moveToLeft(restartLeft, 0); + + return _check->height(); +} + +void UpdateStateRow::paintEvent(QPaintEvent *e) { + Painter p(this); + + auto text = ([this]() -> QString { + switch (_state) { + case State::Check: return lang(lng_settings_update_checking); + case State::Latest: return lang(lng_settings_latest_installed); + case State::Download: return _downloadText; + case State::Ready: return lang(lng_settings_update_ready); + case State::Fail: return lang(lng_settings_update_fail); + default: return QString(); + } + })(); + p.setFont(st::linkFont); + p.setPen(st::settingsUpdateFg); + p.drawTextLeft(0, 0, width(), text); +} + +void UpdateStateRow::onCheck() { + if (!cAutoUpdate()) return; + + cSetLastUpdateCheck(0); + Sandbox::startUpdateCheck(); +} + +void UpdateStateRow::setState(State state, bool force) { + if (_state != state || force) { + _state = state; + switch (state) { + case State::None: + case State::Latest: _check->show(); _restart->hide(); break; + case State::Ready: _check->hide(); _restart->show(); break; + case State::Check: + case State::Download: + case State::Fail: _check->hide(); _restart->hide(); break; + } + resizeToWidth(width()); + sendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton); + update(); + } +} + +void UpdateStateRow::setDownloadProgress(qint64 ready, qint64 total) { + auto readyTenthMb = (ready * 10 / (1024 * 1024)), totalTenthMb = (total * 10 / (1024 * 1024)); + auto readyStr = QString::number(readyTenthMb / 10) + '.' + QString::number(readyTenthMb % 10); + auto totalStr = QString::number(totalTenthMb / 10) + '.' + QString::number(totalTenthMb % 10); + auto result = lng_settings_downloading(lt_ready, readyStr, lt_total, totalStr); + if (_downloadText != result) { + _downloadText = result; + update(); + } +} + +void UpdateStateRow::onChecking() { + setState(State::Check); +} + +void UpdateStateRow::onLatest() { + setState(State::Latest); +} + +void UpdateStateRow::onDownloading(qint64 ready, qint64 total) { + setState(State::Download); + setDownloadProgress(ready, total); +} + +void UpdateStateRow::onReady() { + setState(State::Ready); +} + +void UpdateStateRow::onFailed() { + setState(State::Fail); +} +#endif // TDESKTOP_DISABLE_AUTOUPDATE + GeneralWidget::GeneralWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_general)) , _changeLanguage(this, lang(lng_settings_change_lang)) { connect(_changeLanguage, SIGNAL(clicked()), this, SLOT(onChangeLanguage())); + subscribe(Global::RefChooseCustomLang(), [this]() { chooseCustomLang(); }); + FileDialog::registerObserver(this, &GeneralWidget::notifyFileQueryUpdated); refreshControls(); } @@ -70,7 +188,8 @@ void GeneralWidget::refreshControls() { #ifndef TDESKTOP_DISABLE_AUTOUPDATE addChildRow(_updateAutomatically, marginSub, lng_settings_update_automatically(lt_version, currentVersion()), SLOT(onUpdateAutomatically()), cAutoUpdate()); style::margins marginLink(st::defaultCheckbox.textPosition.x(), 0, 0, st::settingsSkip); - addChildRow(_checkForUpdates, marginLink, lang(lng_settings_check_now), SLOT(onCheckForUpdates())); + addChildRow(_updateRow, marginLink, slidedPadding); + connect(_updateRow->entity(), SIGNAL(restart()), this, SLOT(onRestart())); #endif // TDESKTOP_DISABLE_AUTOUPDATE if (cPlatform() == dbipWindows || cSupportTray()) { @@ -132,17 +251,36 @@ void GeneralWidget::onSaveTestLanguage() { cSetLangFile(_testLanguage); cSetLang(languageTest); Local::writeSettings(); + onRestart(); +} + +void GeneralWidget::onRestart() { +#ifndef TDESKTOP_DISABLE_AUTOUPDATE + checkReadyUpdate(); + if (_updateRow->entity()->isUpdateReady()) { + cSetRestartingUpdate(true); + } else { + cSetRestarting(true); + cSetRestartingToSettings(true); + } +#else cSetRestarting(true); + cSetRestartingToSettings(true); +#endif App::quit(); } #ifndef TDESKTOP_DISABLE_AUTOUPDATE void GeneralWidget::onUpdateAutomatically() { - -} - -void GeneralWidget::onCheckForUpdates() { - + cSetAutoUpdate(_updateAutomatically->checked()); + Local::writeSettings(); + if (cAutoUpdate()) { + _updateRow->slideDown(); + Sandbox::startUpdateCheck(); + } else { + _updateRow->slideUp(); + Sandbox::stopUpdate(); + } } #endif // TDESKTOP_DISABLE_AUTOUPDATE diff --git a/Telegram/SourceFiles/settings/settings_general_widget.h b/Telegram/SourceFiles/settings/settings_general_widget.h index 4778088d4d..ca6551fad7 100644 --- a/Telegram/SourceFiles/settings/settings_general_widget.h +++ b/Telegram/SourceFiles/settings/settings_general_widget.h @@ -33,6 +33,55 @@ class WidgetSlideWrap; namespace Settings { +#ifndef TDESKTOP_DISABLE_AUTOUPDATE +class UpdateStateRow : public TWidget { + Q_OBJECT + +public: + UpdateStateRow(QWidget *parent); + + bool isUpdateReady() const { + return (_state == State::Ready); + } + +protected: + int resizeGetHeight(int newWidth) override; + + void paintEvent(QPaintEvent *e) override; + +signals: + void restart(); + +private slots: + void onCheck(); + + void onChecking(); + void onLatest(); + void onDownloading(qint64 ready, qint64 total); + void onReady(); + void onFailed(); + +private: + enum class State { + None, + Check, + Latest, + Download, + Fail, + Ready + }; + void setState(State state, bool force = false); + void setDownloadProgress(qint64 ready, qint64 total); + + ChildWidget _check; + ChildWidget _restart; + + State _state = State::None; + QString _downloadText; + +}; +#endif // TDESKTOP_DISABLE_AUTOUPDATE + class GeneralWidget : public BlockWidget { Q_OBJECT @@ -48,7 +97,6 @@ private slots: #ifndef TDESKTOP_DISABLE_AUTOUPDATE void onUpdateAutomatically(); - void onCheckForUpdates(); #endif // TDESKTOP_DISABLE_AUTOUPDATE void onEnableTrayIcon(); @@ -58,6 +106,8 @@ private slots: void onStartMinimized(); void onAddInSendTo(); + void onRestart(); + private: void refreshControls(); void updateWorkmode(); @@ -67,7 +117,7 @@ private: ChildWidget _changeLanguage; #ifndef TDESKTOP_DISABLE_AUTOUPDATE ChildWidget _updateAutomatically = { nullptr }; - ChildWidget _checkForUpdates = { nullptr }; + ChildWidget> _updateRow = { nullptr }; #endif // TDESKTOP_DISABLE_AUTOUPDATE ChildWidget _enableTrayIcon = { nullptr }; ChildWidget _enableTaskbarIcon = { nullptr }; diff --git a/Telegram/SourceFiles/settings/settings_privacy_widget.cpp b/Telegram/SourceFiles/settings/settings_privacy_widget.cpp index 3303cd7c09..972ea269db 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_widget.cpp @@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "styles/style_settings.h" #include "lang.h" +#include "boxes/sessionsbox.h" namespace Settings { @@ -49,7 +50,7 @@ void PrivacyWidget::onEditPassword() { } void PrivacyWidget::onShowSessions() { - + Ui::showLayer(new SessionsBox()); } } // namespace Settings diff --git a/Telegram/SourceFiles/settings/settings_privacy_widget.h b/Telegram/SourceFiles/settings/settings_privacy_widget.h index 7ae26b91eb..cce92d5dea 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_widget.h +++ b/Telegram/SourceFiles/settings/settings_privacy_widget.h @@ -24,6 +24,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Settings { +class LocalPasscodeState : public TWidget { +}; + +class CloudPasswordState : public TWidget { +}; + class PrivacyWidget : public BlockWidget { Q_OBJECT @@ -38,6 +44,9 @@ private slots: private: void refreshControls(); + //ChildWidget _localPasscodeState = { nullptr }; + //ChildWidget> _autoLock = { nullptr }; + //ChildWidget _cloudPasswordState = { nullptr }; ChildWidget _editPasscode = { nullptr }; ChildWidget _editPassword = { nullptr }; ChildWidget _showAllSessions = { nullptr }; diff --git a/Telegram/SourceFiles/settings/settings_widget.cpp b/Telegram/SourceFiles/settings/settings_widget.cpp index d76716a738..5c591cb000 100644 --- a/Telegram/SourceFiles/settings/settings_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_widget.cpp @@ -26,8 +26,94 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "styles/style_settings.h" #include "ui/scrollarea.h" #include "mainwindow.h" +#include "localstorage.h" +#include "boxes/confirmbox.h" +#include "application.h" namespace Settings { +namespace { + +QString SecretText; +QMap> Codes; + +void fillCodes() { + Codes.insert(qsl("debugmode"), []() { + QString text = cDebug() ? qsl("Do you want to disable DEBUG logs?") : qsl("Do you want to enable DEBUG logs?\n\nAll network events will be logged."); + ConfirmBox *box = new ConfirmBox(text); + box->connect(box, SIGNAL(confirmed()), App::app(), SLOT(onSwitchDebugMode())); + Ui::showLayer(box); + }); + Codes.insert(qsl("testmode"), []() { + QString text = cTestMode() ? qsl("Do you want to disable TEST mode?") : qsl("Do you want to enable TEST mode?\n\nYou will be switched to test cloud."); + ConfirmBox *box = new ConfirmBox(text); + box->connect(box, SIGNAL(confirmed()), App::app(), SLOT(onSwitchTestMode())); + Ui::showLayer(box); + }); + Codes.insert(qsl("loadlang"), []() { + Global::RefChooseCustomLang().notify(); + }); + Codes.insert(qsl("debugfiles"), []() { + if (!cDebug()) return; + if (DebugLogging::FileLoader()) { + Global::RefDebugLoggingFlags() &= ~DebugLogging::FileLoaderFlag; + } else { + Global::RefDebugLoggingFlags() |= DebugLogging::FileLoaderFlag; + } + Ui::showLayer(new InformBox(DebugLogging::FileLoader() ? qsl("Enabled file download logging") : qsl("Disabled file download logging"))); + }); + Codes.insert(qsl("crashplease"), []() { + t_assert(!"Crashed in Settings!"); + }); + Codes.insert(qsl("workmode"), []() { + auto text = Global::DialogsModeEnabled() ? qsl("Disable work mode?") : qsl("Enable work mode?"); + auto box = std_::make_unique(text); + box->connect(box.get(), SIGNAL(confirmed()), App::app(), SLOT(onSwitchWorkMode())); + Ui::showLayer(box.release()); + }); + Codes.insert(qsl("moderate"), []() { + auto text = Global::ModerateModeEnabled() ? qsl("Disable moderate mode?") : qsl("Enable moderate mode?"); + auto box = std_::make_unique(text); + box->setConfirmedCallback([]() { + Global::SetModerateModeEnabled(!Global::ModerateModeEnabled()); + Local::writeUserSettings(); + Ui::hideLayer(); + }); + Ui::showLayer(box.release()); + }); +} + +void codesFeedString(const QString &text) { + if (Codes.isEmpty()) fillCodes(); + + SecretText += text.toLower(); + int size = SecretText.size(), from = 0; + while (size > from) { + auto piece = SecretText.midRef(from); + auto found = false; + for (auto i = Codes.cbegin(), e = Codes.cend(); i != e; ++i) { + if (piece == i.key()) { + (*i)(); + from = size; + found = true; + break; + } + } + if (found) break; + + for (auto i = Codes.cbegin(), e = Codes.cend(); i != e; ++i) { + if (i.key().startsWith(piece)) { + found = true; + break; + } + } + if (found) break; + + ++from; + } + SecretText = (size > from) ? SecretText.mid(from) : QString(); +} + +} // namespace Widget::Widget() : LayerWidget() , _scroll(this, st::setScroll) @@ -127,4 +213,9 @@ void Widget::resizeEvent(QResizeEvent *e) { } } +void Widget::keyPressEvent(QKeyEvent *e) { + codesFeedString(e->text()); + return LayerWidget::keyPressEvent(e); +} + } // namespace Settings diff --git a/Telegram/SourceFiles/settings/settings_widget.h b/Telegram/SourceFiles/settings/settings_widget.h index c96e9546cd..b7912e47ce 100644 --- a/Telegram/SourceFiles/settings/settings_widget.h +++ b/Telegram/SourceFiles/settings/settings_widget.h @@ -39,6 +39,7 @@ public: protected: void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; private slots: void onInnerHeightUpdated(); diff --git a/Telegram/SourceFiles/ui/twidget.cpp b/Telegram/SourceFiles/ui/twidget.cpp index 54af7cc611..160f875bbc 100644 --- a/Telegram/SourceFiles/ui/twidget.cpp +++ b/Telegram/SourceFiles/ui/twidget.cpp @@ -121,9 +121,10 @@ void ToggleableShadow::paintEvent(QPaintEvent *e) { } void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button, const QPoint &globalPoint) { - auto windowHandle = widget->window()->windowHandle(); - auto localPoint = windowHandle->mapFromGlobal(globalPoint); - QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, QGuiApplication::mouseButtons() | button, QGuiApplication::keyboardModifiers(), Qt::MouseEventSynthesizedByApplication); - ev.setTimestamp(getms()); - QGuiApplication::sendEvent(windowHandle, &ev); + if (auto windowHandle = widget->window()->windowHandle()) { + auto localPoint = windowHandle->mapFromGlobal(globalPoint); + QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, QGuiApplication::mouseButtons() | button, QGuiApplication::keyboardModifiers(), Qt::MouseEventSynthesizedByApplication); + ev.setTimestamp(getms()); + QGuiApplication::sendEvent(windowHandle, &ev); + } } diff --git a/Telegram/SourceFiles/ui/widgets/widget_slide_wrap.h b/Telegram/SourceFiles/ui/widgets/widget_slide_wrap.h index 55cf18c2da..9f8cfbb36b 100644 --- a/Telegram/SourceFiles/ui/widgets/widget_slide_wrap.h +++ b/Telegram/SourceFiles/ui/widgets/widget_slide_wrap.h @@ -118,7 +118,8 @@ public: } int naturalWidth() const override { - return _padding.top() + _entity->naturalWidth() + _padding.bottom(); + auto inner = _entity->naturalWidth(); + return (inner < 0) ? inner : (_padding.left() + inner + _padding.right()); } protected: