statuswidget.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. #include "ui_statuswidget.h"
  2. #include "statuswidget.h"
  3. #include "models/patchdownloader.h"
  4. #include "models/settings.h"
  5. #include "legacyapplication.h"
  6. #include "constants.h"
  7. #include <QDesktopServices>
  8. #include <QUrl>
  9. #include <QDebug>
  10. #include <QMessageBox>
  11. #include <QRandomGenerator>
  12. StatusWidget::StatusWidget(QWidget *parent)
  13. : QWidget(parent)
  14. , ui(new Ui::StatusWidget)
  15. {
  16. ui->setupUi(this);
  17. last_statusbar_update_time_.start();
  18. ui->galadriel_tooltip_example->hide();
  19. ui->c_progress_bar->setProgress(100);
  20. connect(ui->weekly_code_widget, &WeeklyCodeWidget::showCompletedTooltip, this, [this](){setToolTipMessage("Еженедельный код скопирован в буфер обмена.", E_HINT);});
  21. connect(ui->weekly_code_widget, &WeeklyCodeWidget::showHelpTooltip, this, [this](){setToolTipMessage("Нажмите по еженедельному коду, чтобы скопировать его.", E_HINT);});
  22. connect(ui->weekly_code_widget, &WeeklyCodeWidget::showNoTooltip, this, [this](){unsetToolTipMessage(E_HINT);});
  23. connect(ui->news_list, &NewsListWidget::showHelpToolTip, this, [this](){setToolTipMessage("Нажмите на заголовок новости, чтобы открыть её в браузере.", E_HINT);});
  24. connect(ui->news_list, &NewsListWidget::showNoToolTip, this, [this](){unsetToolTipMessage(E_HINT);});
  25. connect(ui->server_status_widget, &ServerStatusWidget::showServersTooltip, this, [this](QString message){setToolTipMessage(message, E_HINT);});
  26. connect(ui->server_status_widget, &ServerStatusWidget::showNoTooltip, this, [this](){unsetToolTipMessage(E_HINT);});
  27. connect(&PatchDownloader::instance(), &PatchDownloader::started, this, &StatusWidget::onPatchDownloaderStarted);
  28. connect(&PatchDownloader::instance(), &PatchDownloader::progressChanged, this, &StatusWidget::onPatchDownloaderProgressChanged);
  29. connect(&PatchDownloader::instance(), &PatchDownloader::finished, this, &StatusWidget::onPatchDownloaderFinished);
  30. connect(&PatchInstaller::instance(), &PatchInstaller::started, this, &StatusWidget::onPatchInstallerStarted);
  31. connect(&PatchInstaller::instance(), &PatchInstaller::progressChanged, this, &StatusWidget::onPatchInstallerProgressChanged);
  32. connect(&PatchInstaller::instance(), &PatchInstaller::finished, this, &StatusWidget::onPatchInstallerFinished);
  33. connect(&PatchInstaller::instance(), &PatchInstaller::videosDownloadProgressChanged, this, &StatusWidget::onPatchInstallerVideoProgressChanged);
  34. connect(&PatchInstaller::instance(), &PatchInstaller::successfullyInitialized, this, &StatusWidget::showComponentsStatus);
  35. connect(&PatchInstaller::instance(), &PatchInstaller::deinitialized, this, &StatusWidget::hideComponentsStatus);
  36. connect(&LegacyApplication::instance(), &LegacyApplication::ErrorStatusChanged, this, &StatusWidget::onErrorStatusChanged);
  37. connect(ui->b_components_status, &TranslationComponents::needToPatch, this, &StatusWidget::onTranslationComponentsNeedToPatch);
  38. connect(ui->b_components_status, &TranslationComponents::noNeedToPatch, this, &StatusWidget::onTranslationComponentsNoNeedToPatch);
  39. connect(&PatchDownloader::instance(), &PatchDownloader::checkForUpdatesStatusChanged, this, [this](bool need_update){_need_to_update = need_update; updateButtonStatus();});
  40. connect(&PatchInstaller::instance(), &PatchInstaller::finished, this, [this](){_need_to_install_patches = false; updateButtonStatus();});
  41. ui->b_components_status->hide();
  42. _components_status_opacity_effect = new QGraphicsOpacityEffect();
  43. _components_status_opacity_animation = new QPropertyAnimation(_components_status_opacity_effect, "opacity");
  44. _components_status_opacity_animation->setStartValue(0);
  45. _components_status_opacity_animation->setDuration(1000);
  46. ui->b_components_status->setGraphicsEffect(_components_status_opacity_effect);
  47. }
  48. StatusWidget::~StatusWidget()
  49. {
  50. _components_status_opacity_animation->stop();
  51. _components_status_opacity_animation->deleteLater();
  52. _components_status_opacity_effect->deleteLater();
  53. delete ui;
  54. }
  55. void StatusWidget::updateFontsSizes()
  56. {
  57. ui->game_button->setFont(trajan_11pt);
  58. ui->news_label->setFont(trajan_10pt);
  59. }
  60. void StatusWidget::setToolTipMessage(QString message, StatusWidget::ToolTipState state)
  61. {
  62. tooltip_messages_[state] = message;
  63. tooltip_state_ = ToolTipState(int(tooltip_state_) | int(state));
  64. QString message_id = message;
  65. if (state == E_PROCESS) {
  66. message_id = "E_PROCESS";
  67. }
  68. if (tooltip_state_ < state * 2) {
  69. if (!tooltip_widgets_.contains(message_id)) {
  70. createTooltipMessageWidget(message_id);
  71. }
  72. tooltip_widgets_[message_id]->setText(message);
  73. fadeBetweenToolTips(message_id);
  74. }
  75. }
  76. void StatusWidget::unsetToolTipMessage(StatusWidget::ToolTipState state)
  77. {
  78. tooltip_state_ = ToolTipState(int(tooltip_state_) & (~int(state)));
  79. ToolTipState showing_state = E_RANDOM;
  80. if (tooltip_state_ & E_INFO) {
  81. showing_state = E_INFO;
  82. } else if (tooltip_state_ & E_PROCESS) {
  83. showing_state = E_PROCESS;
  84. } else if (tooltip_state_ & E_HINT) {
  85. showing_state = E_HINT;
  86. }
  87. QString message_id = tooltip_messages_[showing_state];
  88. if (showing_state == E_PROCESS) {
  89. message_id = "E_PROCESS";
  90. }
  91. if (!tooltip_widgets_.contains(message_id)) {
  92. createTooltipMessageWidget(message_id);
  93. }
  94. tooltip_widgets_[message_id]->setText(tooltip_messages_[showing_state]);
  95. fadeBetweenToolTips(message_id);
  96. }
  97. void StatusWidget::onErrorStatusChanged(AppErrorStatus status)
  98. {
  99. QString init_error_type_message;
  100. if (status == E_NO_ERRORS) {
  101. setToolTipMessage("Инициализация Наследия прошла успешно!", E_INFO);
  102. ui->news_list->updateNewsWidget();
  103. ui->server_status_widget->updateServerStatus();
  104. ui->weekly_code_widget->updateWeeklyCodeWidget();
  105. return;
  106. } else if (status == E_WRONG_GAME_FOLDER) {
  107. const QString game_path = Settings::getValue("Lotro/game_path").toString();
  108. if (game_path == "none") {
  109. init_error_type_message = "Добро пожаловать в Наследие!\nПожалуйста, выберите папку с игрой.";
  110. } else {
  111. init_error_type_message = "Добро пожаловать в Наследие!\nНе найдены файлы игры, пожалуйста, выберите корректную папку с игрой!";
  112. }
  113. } else if (status == E_DAT_FILES_MISSING) {
  114. init_error_type_message = "Некоторые файлы данных игры не найдены.\nНажмите на кнопку \"Исправить\", чтобы запустить лаунчер игры, который автоматически перекачает нужные файлы.";
  115. } else if (status == E_WRONG_FILE_PERMISSIONS) {
  116. init_error_type_message = "Недостаточно прав для изменения файлов игры.\nПопробуйте запустить Наследие от имени администратора.";
  117. } else if (status == E_DAT_FILE_INCORRECT) {
  118. init_error_type_message = "Некоторые файлы игры несовместимы с этой версией Наследия.\nНажмите на кнопку \"Исправить\", чтобы запустить лаунчер игры, который автоматически скачает нужные файлы.";
  119. } else if (status == E_NO_SERVER_CONNECTION) {
  120. init_error_type_message = "Нет связи с серверами Наследия.\nПожалуйста, проверьте соединение с Интернетом.";
  121. }
  122. setToolTipMessage(init_error_type_message, E_INFO);
  123. }
  124. void StatusWidget::resizeEvent(QResizeEvent *)
  125. {
  126. double coefficient = window_width / default_window_width;
  127. // ui->game_button->move(QPoint(820, 460) * coefficient);
  128. // ui->game_button->resize(QSize(150, 60) * coefficient);
  129. // ui->progressBar->move(QPoint(320, 480) * coefficient);
  130. // ui->progressBar->resize(QSize(470, 40) * coefficient);
  131. // ui->progress_label->move(QPoint(330, 390) * coefficient);
  132. // ui->progress_label->resize(QSize(380, 90) * coefficient);
  133. // ui->news_label->move(QPoint(45, 33)* coefficient);
  134. // ui->news_label->resize(QSize(180, 21) * coefficient);
  135. // ui->news_scroll_area->move(QPoint(40, 75) * coefficient);
  136. // ui->news_scroll_area->resize(QSize(240, 440) * coefficient);
  137. // ui->server_status_widget->move(QPoint(820, 90) * coefficient);
  138. // ui->server_status_widget->resize(QSize(155, 320) * coefficient);
  139. // ui->weekly_code_widget->move(QPoint(810, 13) * coefficient);
  140. // ui->weekly_code_widget->resize(QSize(173, 57) * coefficient);
  141. // ui->galadriel_widget->move(QPoint(320, 20) * coefficient);
  142. // ui->galadriel_widget->resize(QSize(531, 461) * coefficient);
  143. // ui->news_tooltip->move(QPoint(38, 13) * coefficient);
  144. // ui->news_tooltip->resize(QSize(365, 114) * coefficient);
  145. // ui->weekly_code_tooltip_1->move(QPoint(38, 13) * coefficient);
  146. // ui->weekly_code_tooltip_1->resize(QSize(365, 114) * coefficient);
  147. // ui->weekly_code_tooltip_2->move(QPoint(38, 13) * coefficient);
  148. // ui->weekly_code_tooltip_2->resize(QSize(365, 114) * coefficient);
  149. // ui->server_status_tooltip->move(QPoint(38, 13) * coefficient);
  150. // ui->server_status_tooltip->resize(QSize(365, 114) * coefficient);
  151. // ui->patches_status->move(QPoint(38, 13) * coefficient);
  152. // ui->patches_status->resize(QSize(385, 114) * coefficient);
  153. updateFontsSizes();
  154. }
  155. void StatusWidget::generateRandomTooltipMessage()
  156. {
  157. quint32 number = QRandomGenerator::system()->generate();
  158. QVector<QString> messages = {
  159. "<p style=\"font-size: 22px; \">Atra du evarínya ono varda! Я видела тебя в своём зеркале...</p>",
  160. "<p style=\"font-size: 22px; \">Опасно ходить в рейды в одиночку! Зачищать инсты лучше в хорошей компании :)</p>",
  161. "<p style=\"font-size: 22px; \">Какое-то ещё мудрое высказывание в стиле эльфов...</p>",
  162. "<p style=\"font-size: 22px; \">Мудрые сидят в дискорде Наследия, <a href=\"https://discord.gg/j25MdKR\" style=\"color: yellow\">присоединяйся</a>!</p>",
  163. };
  164. setToolTipMessage(messages[number % messages.size()], E_RANDOM);
  165. }
  166. void StatusWidget::fadeBetweenToolTips(QString tooltip_id)
  167. {
  168. if (tooltip_id == current_tooltip_message_) {
  169. return;
  170. }
  171. QPropertyAnimation* showing_anim = tooltip_animations_[tooltip_id];
  172. showing_anim->setDirection(QAbstractAnimation::Forward);
  173. if (showing_anim->state() == QAbstractAnimation::Stopped) {
  174. showing_anim->start();
  175. }
  176. if (tooltip_widgets_.contains(current_tooltip_message_)) {
  177. QString msg = current_tooltip_message_;
  178. connect(tooltip_animations_[current_tooltip_message_], &QPropertyAnimation::finished, this, [&, msg](){
  179. if (tooltip_effects_.contains(msg) && tooltip_effects_[msg]->opacity() == 0) {
  180. tooltip_widgets_.take(msg)->deleteLater();
  181. tooltip_effects_.take(msg)->deleteLater();
  182. tooltip_animations_.take(msg)->deleteLater();
  183. }
  184. });
  185. QPropertyAnimation* hiding_anim = tooltip_animations_[current_tooltip_message_];
  186. hiding_anim->setDirection(QAbstractAnimation::Backward);
  187. if (hiding_anim->state() == QAbstractAnimation::Stopped) {
  188. hiding_anim->start();
  189. }
  190. }
  191. current_tooltip_message_ = tooltip_id;
  192. }
  193. void StatusWidget::onPatchDownloaderStarted() {
  194. all_patch_operations_finished_ = false;
  195. ui->game_button->setEnabled(false);
  196. setToolTipMessage("Проверка обновлений русификации...", E_PROCESS);
  197. }
  198. void StatusWidget::onPatchDownloaderFinished() {
  199. all_patch_operations_finished_ = true;
  200. ui->game_button->setEnabled(true);
  201. unsetToolTipMessage(E_PROCESS);
  202. }
  203. void StatusWidget::onPatchDownloaderProgressChanged(Downloader::Status status) {
  204. double download_percent = status.total_bytes > 0 ? double(status.downloaded_bytes) * 100.0 / double(status.total_bytes) : 100;
  205. ui->c_progress_bar->setProgress(download_percent);
  206. if (last_statusbar_update_time_.elapsed() > 450) {
  207. QString text = "Загрузка данных: " + QString::number(download_percent, 'f', 1) + "% ("
  208. + Downloader::getSizeFormatted(status.downloaded_bytes) + "/"
  209. + Downloader::getSizeFormatted(status.total_bytes) + ")\n"
  210. + "До конца загрузки: " + Downloader::getElapsedTimeFormatted(status.elapsed_time);
  211. setToolTipMessage(text, E_PROCESS);
  212. last_statusbar_update_time_.restart();
  213. }
  214. }
  215. void StatusWidget::onPatchInstallerStarted() {
  216. all_patch_operations_finished_ = false;
  217. ui->game_button->setEnabled(false);
  218. setToolTipMessage("Начинаем установку компонент русификации...", E_PROCESS);
  219. }
  220. void StatusWidget::onPatchInstallerFinished() {
  221. all_patch_operations_finished_ = true;
  222. ui->game_button->setEnabled(true);
  223. unsetToolTipMessage(E_PROCESS);
  224. }
  225. void StatusWidget::onPatchInstallerProgressChanged(PatchInstaller::Status status) {
  226. double install_percent = status.total_parts > 0 ? double(status.finished_parts) * 100.0 / double(status.total_parts) : 100;
  227. ui->c_progress_bar->setProgress(install_percent);
  228. if (last_statusbar_update_time_.elapsed() > 450 || status.finished_parts == 0) {
  229. QString text = "Установка русификации: "
  230. + QString::number(double(status.finished_parts) * 100.0 / double(status.total_parts), 'f', 1)
  231. + "%\n(" + QString::number(status.finished_parts)
  232. + " фрагментов из " + QString::number(status.total_parts) + ")";
  233. setToolTipMessage(text, E_PROCESS);
  234. last_statusbar_update_time_.restart();
  235. }
  236. }
  237. void StatusWidget::onPatchInstallerVideoProgressChanged(int finished_videos, int total_videos, Downloader::Status status) {
  238. if (last_statusbar_update_time_.elapsed() > 450) {
  239. double download_percent = double(status.downloaded_bytes) * 100.0 / double(status.total_bytes);
  240. QString text = "Загрузка и установка видеороликов ("
  241. + QString::number(finished_videos + 1) + " из " + QString::number(total_videos)
  242. + ")\n"
  243. + "Загружено: " + QString::number(download_percent, 'f', 1) + "% ("
  244. + Downloader::getSizeFormatted(status.downloaded_bytes) + "/"
  245. + Downloader::getSizeFormatted(status.total_bytes) + ")";
  246. setToolTipMessage(text, E_PROCESS);
  247. last_statusbar_update_time_.restart();
  248. }
  249. }
  250. void StatusWidget::on_game_button_clicked()
  251. {
  252. if (_need_to_update || _need_to_install_patches) {
  253. QMetaObject::invokeMethod(&PatchDownloader::instance(), &PatchDownloader::startPatchDownloaderChain, Qt::QueuedConnection);
  254. return;
  255. }
  256. QMetaObject::invokeMethod(&PatchInstaller::instance(), &PatchInstaller::startGame, Qt::QueuedConnection);
  257. }
  258. void StatusWidget::createTooltipMessageWidget(QString tooltip_id)
  259. {
  260. tooltip_widgets_[tooltip_id] = new QLabel(this);
  261. tooltip_widgets_[tooltip_id]->setGeometry(ui->galadriel_tooltip_example->geometry());
  262. tooltip_widgets_[tooltip_id]->setStyleSheet(ui->galadriel_tooltip_example->styleSheet());
  263. tooltip_widgets_[tooltip_id]->setFont(ui->galadriel_tooltip_example->font());
  264. tooltip_widgets_[tooltip_id]->setWordWrap(true);
  265. tooltip_widgets_[tooltip_id]->setOpenExternalLinks(true);
  266. tooltip_widgets_[tooltip_id]->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
  267. tooltip_effects_[tooltip_id] = new QGraphicsOpacityEffect(tooltip_widgets_[tooltip_id]);
  268. tooltip_effects_[tooltip_id]->setOpacity(0);
  269. tooltip_animations_[tooltip_id] = new QPropertyAnimation(tooltip_effects_[tooltip_id], "opacity");
  270. tooltip_animations_[tooltip_id]->setDuration(300);
  271. tooltip_animations_[tooltip_id]->setStartValue(0);
  272. tooltip_animations_[tooltip_id]->setEndValue(1);
  273. tooltip_animations_[tooltip_id]->setDirection(QAbstractAnimation::Forward);
  274. tooltip_widgets_[tooltip_id]->setGraphicsEffect(tooltip_effects_[tooltip_id]);
  275. tooltip_widgets_[tooltip_id]->show();
  276. }
  277. void StatusWidget::on_check_for_updates_button_clicked()
  278. {
  279. QMetaObject::invokeMethod(&PatchDownloader::instance(), &PatchDownloader::startPatchDownloaderChain, Qt::QueuedConnection);
  280. }
  281. void StatusWidget::showComponentsStatus() {
  282. _components_status_opacity_animation->disconnect();
  283. if (_components_status_opacity_animation->state() == QAbstractAnimation::Running) {
  284. _components_status_opacity_animation->pause();
  285. }
  286. ui->b_components_status->show();
  287. _components_status_opacity_animation->setEndValue(1);
  288. if (_components_status_opacity_animation->state() == QAbstractAnimation::Stopped) {
  289. _components_status_opacity_animation->start();
  290. } else {
  291. _components_status_opacity_animation->resume();
  292. }
  293. }
  294. void StatusWidget::hideComponentsStatus() {
  295. if (this->isVisible()) {
  296. if (_components_status_opacity_animation->state() == QAbstractAnimation::Running) {
  297. _components_status_opacity_animation->pause();
  298. }
  299. _components_status_opacity_animation->setEndValue(0);
  300. if (_components_status_opacity_animation->state() == QAbstractAnimation::Stopped) {
  301. _components_status_opacity_animation->start();
  302. } else {
  303. _components_status_opacity_animation->resume();
  304. }
  305. connect(_components_status_opacity_animation, &QPropertyAnimation::finished, ui->b_components_status, &QWidget::hide);
  306. }
  307. }
  308. void StatusWidget::onTranslationComponentsNeedToPatch() {
  309. _need_to_install_patches = true;
  310. updateButtonStatus();
  311. }
  312. void StatusWidget::onTranslationComponentsNoNeedToPatch() {
  313. _need_to_install_patches = false;
  314. updateButtonStatus();
  315. }
  316. void StatusWidget::updateButtonStatus() {
  317. if (_need_to_update) {
  318. setToolTipMessage("Доступны обновления русификации.\nНажмите \"Обновить\", чтобы начать загрузку.", ToolTipState::E_INFO);
  319. ui->game_button->setText("ОБНОВИТЬ");
  320. ui->game_button->setStyleSheet("QPushButton#game_button { \n color: white;\n border-image: url(:/buttons/button_big_yellow.png);\n}\n\nQPushButton#game_button:hover {\n color: white;\n border-image: url(:/buttons/button_big_yellow_over.png);\n}\n\nQPushButton#game_button:pressed {\n color: white;\n border-image: url(:/buttons/button_big_yellow_pressed.png);\n}\n\nQPushButton#game_button:disabled {\n color: white;\n border-image: url(:/buttons/button_big_disabled.png);\n}\n");
  321. } else if (_need_to_install_patches) {
  322. setToolTipMessage("Выбранные компоненты требуют установки.\nНажмите \"Установить\", чтобы начать их установку.", ToolTipState::E_INFO);
  323. ui->game_button->setText("установить");
  324. ui->game_button->setStyleSheet("QPushButton#game_button { \n color: white;\n border-image: url(:/buttons/button_big_yellow.png);\n}\n\nQPushButton#game_button:hover {\n color: white;\n border-image: url(:/buttons/button_big_yellow_over.png);\n}\n\nQPushButton#game_button:pressed {\n color: white;\n border-image: url(:/buttons/button_big_yellow_pressed.png);\n}\n\nQPushButton#game_button:disabled {\n color: white;\n border-image: url(:/buttons/button_big_disabled.png);\n}\n");
  325. } else {
  326. setToolTipMessage("Установлена последняя версия русификации.\nНажмите \"Играть\", чтобы запустить игру.", ToolTipState::E_INFO);
  327. ui->game_button->setText("ИГРАТЬ");
  328. ui->game_button->setStyleSheet("QPushButton#game_button { \n color: white;\n border-image: url(:/buttons/button_big_normal.png);\n}\n\nQPushButton#game_button:hover {\n color: white;\n border-image: url(:/buttons/button_big_over.png);\n}\n\nQPushButton#game_button:pressed {\n color: white;\n border-image: url(:/buttons/button_big_pressed.png);\n}\n\nQPushButton#game_button:disabled {\n color: white;\n border-image: url(:/buttons/button_big_disabled.png);\n}\n");
  329. }
  330. }