diff --git a/resources/images/download_update_error.png b/resources/images/download_update_error.png new file mode 100644 index 00000000..5c1fec10 Binary files /dev/null and b/resources/images/download_update_error.png differ diff --git a/resources/resources.qrc b/resources/resources.qrc index 146c2c66..cf41c346 100644 --- a/resources/resources.qrc +++ b/resources/resources.qrc @@ -73,6 +73,7 @@ avatars/fourtf.png avatars/pajlada.png images/download_update.png + images/download_update_error.png qt.conf diff --git a/src/singletons/Updates.cpp b/src/singletons/Updates.cpp index 4cadf2b1..c9580939 100644 --- a/src/singletons/Updates.cpp +++ b/src/singletons/Updates.cpp @@ -141,12 +141,40 @@ void Updates::checkForUpdates() #endif } -Updates::UpdateStatus Updates::getStatus() const +Updates::Status Updates::getStatus() const { return this->status_; } -void Updates::setStatus_(UpdateStatus status) +bool Updates::shouldShowUpdateButton() const +{ + switch (this->getStatus()) { + case UpdateAvailable: + case SearchFailed: + case Downloading: + case DownloadFailed: + case WriteFileFailed: + return true; + + default: + return false; + } +} + +bool Updates::isError() const +{ + switch (this->getStatus()) { + case SearchFailed: + case DownloadFailed: + case WriteFileFailed: + return true; + + default: + return false; + } +} + +void Updates::setStatus_(Status status) { if (this->status_ != status) { this->status_ = status; diff --git a/src/singletons/Updates.hpp b/src/singletons/Updates.hpp index f760631a..ff3df8bb 100644 --- a/src/singletons/Updates.hpp +++ b/src/singletons/Updates.hpp @@ -10,7 +10,7 @@ class Updates Updates(); public: - enum UpdateStatus { + enum Status { None, Searching, UpdateAvailable, @@ -28,18 +28,21 @@ public: const QString &getCurrentVersion() const; const QString &getOnlineVersion() const; void installUpdates(); - UpdateStatus getStatus() const; + Status getStatus() const; - pajlada::Signals::Signal statusUpdated; + bool shouldShowUpdateButton() const; + bool isError() const; + + pajlada::Signals::Signal statusUpdated; private: QString currentVersion_; QString onlineVersion_; - UpdateStatus status_ = None; + Status status_ = None; QString updateUrl_; - void setStatus_(UpdateStatus status); + void setStatus_(Status status); }; } // namespace chatterino diff --git a/src/widgets/BaseWindow.cpp b/src/widgets/BaseWindow.cpp index c78096c5..dfcd8b8b 100644 --- a/src/widgets/BaseWindow.cpp +++ b/src/widgets/BaseWindow.cpp @@ -409,6 +409,11 @@ void BaseWindow::resizeEvent(QResizeEvent *) this->calcButtonsSizes(); } +void BaseWindow::closeEvent(QCloseEvent *) +{ + this->closing.invoke(); +} + void BaseWindow::moveIntoDesktopRect(QWidget *parent) { if (!this->stayInScreenRect_) diff --git a/src/widgets/BaseWindow.hpp b/src/widgets/BaseWindow.hpp index 8e6c591e..5baf88b6 100644 --- a/src/widgets/BaseWindow.hpp +++ b/src/widgets/BaseWindow.hpp @@ -52,6 +52,8 @@ public: Flags getFlags(); + pajlada::Signals::NoArgSignal closing; + protected: virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; virtual void scaleChangedEvent(float) override; @@ -61,6 +63,7 @@ protected: virtual void changeEvent(QEvent *) override; virtual void leaveEvent(QEvent *) override; virtual void resizeEvent(QResizeEvent *) override; + virtual void closeEvent(QCloseEvent *) override; virtual void themeRefreshEvent() override; virtual bool event(QEvent *event) override; diff --git a/src/widgets/Window.cpp b/src/widgets/Window.cpp index 23475e9d..5e733abb 100644 --- a/src/widgets/Window.cpp +++ b/src/widgets/Window.cpp @@ -6,6 +6,7 @@ #include "providers/twitch/TwitchServer.hpp" #include "singletons/Settings.hpp" #include "singletons/Theme.hpp" +#include "singletons/Updates.hpp" #include "singletons/WindowManager.hpp" #include "widgets/AccountSwitchPopupWidget.hpp" #include "widgets/Notebook.hpp" @@ -53,27 +54,7 @@ Window::Window(WindowType _type) }); if (this->hasCustomWindowFrame() && _type == Window::Main) { - // settings - this->addTitleBarButton(TitleBarButton::Settings, [app] { - app->windows->showSettingsDialog(); // - }); - - // updates - auto update = this->addTitleBarButton(TitleBarButton::None, [] {}); - update->setPixmap(QPixmap(":/images/download_update.png")); - QObject::connect(update, &TitleBarButton::clicked, this, [this, update] { - auto dialog = new UpdatePromptDialog(); - dialog->setActionOnFocusLoss(BaseWindow::Delete); - dialog->move(update->mapToGlobal(QPoint(-100 * this->getScale(), update->height()))); - dialog->show(); - dialog->raise(); - }); - - // account - this->userLabel = this->addTitleBarLabel([this, app] { - app->windows->showAccountSelectPopup( - this->userLabel->mapToGlobal(this->userLabel->rect().bottomLeft())); // - }); + this->addCustomTitlebarButtons(); } if (_type == Window::Main) { @@ -194,6 +175,54 @@ Window::Window(WindowType _type) this->notebook.setShowAddButton(true); } +void Window::addCustomTitlebarButtons() +{ + // settings + this->addTitleBarButton(TitleBarButton::Settings, [] { + getApp()->windows->showSettingsDialog(); // + }); + + // updates + auto update = this->addTitleBarButton(TitleBarButton::None, [] {}); + update->hide(); + QObject::connect(update, &TitleBarButton::clicked, this, [this, update] { + auto dialog = new UpdatePromptDialog(); + dialog->setActionOnFocusLoss(BaseWindow::Delete); + dialog->move(update->mapToGlobal(QPoint(int(-100 * this->getScale()), update->height()))); + dialog->show(); + dialog->raise(); + + dialog->buttonClicked.connect([update](auto button) { + switch (button) { + case UpdatePromptDialog::Dismiss: { + update->hide(); + } break; + } + }); + + this->updateDialogHandle_.reset(dialog); + dialog->closing.connect([this] { this->updateDialogHandle_.release(); }); + }); + + auto updateChange = [update](auto) { + update->setVisible(Updates::getInstance().shouldShowUpdateButton()); + + auto imageUrl = Updates::getInstance().isError() ? ":/images/download_update_error.png" + : ":/images/download_update.png"; + update->setPixmap(QPixmap(imageUrl)); + }; + + updateChange(Updates::getInstance().getStatus()); + this->signalHolder.managedConnect(Updates::getInstance().statusUpdated, + [updateChange](auto status) { updateChange(status); }); + + // account + this->userLabel = this->addTitleBarLabel([this] { + getApp()->windows->showAccountSelectPopup( + this->userLabel->mapToGlobal(this->userLabel->rect().bottomLeft())); // + }); +} + Window::WindowType Window::getType() { return this->type; diff --git a/src/widgets/Window.hpp b/src/widgets/Window.hpp index 60bf8be8..60ce046c 100644 --- a/src/widgets/Window.hpp +++ b/src/widgets/Window.hpp @@ -10,10 +10,12 @@ #include #include +#include namespace chatterino { class Theme; +class UpdatePromptDialog; class Window : public BaseWindow { @@ -40,15 +42,19 @@ protected: bool event(QEvent *event) override; private: + void addCustomTitlebarButtons(); + void loadGeometry(); + RippleEffectLabel *userLabel = nullptr; + std::unique_ptr updateDialogHandle_; WindowType type; float dpi; - void loadGeometry(); - SplitNotebook notebook; + pajlada::Signals::SignalHolder signalHolder; + friend class Notebook; public: diff --git a/src/widgets/dialogs/UpdatePromptDialog.cpp b/src/widgets/dialogs/UpdatePromptDialog.cpp index 2cc4df2a..a8b36c38 100644 --- a/src/widgets/dialogs/UpdatePromptDialog.cpp +++ b/src/widgets/dialogs/UpdatePromptDialog.cpp @@ -1,5 +1,6 @@ #include "UpdatePromptDialog.hpp" +#include "singletons/Updates.hpp" #include "util/LayoutCreator.hpp" #include "widgets/Label.hpp" @@ -15,16 +16,53 @@ UpdatePromptDialog::UpdatePromptDialog() { auto layout = LayoutCreator(this).setLayoutType(); - layout.emplace