statuswidget.cpp 19 KB

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