mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-18 09:53:05 +08:00
[feat] add in-app Windows updates with automatic download and setup launch
This commit is contained in:
@@ -1413,6 +1413,21 @@ void GuiApplication::BindMainCallbacks() {
|
||||
: slint::SharedString{});
|
||||
});
|
||||
main->on_open_download([this] { OpenUrl("https://crossdesk.cn"); });
|
||||
main->on_start_update([this] {
|
||||
#if _WIN32
|
||||
windows_updater_.Start(latest_version_info_);
|
||||
SyncWindowsUpdate();
|
||||
#else
|
||||
OpenUrl("https://crossdesk.cn");
|
||||
ui_->main->set_update_open(false);
|
||||
#endif
|
||||
});
|
||||
main->on_cancel_update([this] {
|
||||
#if _WIN32
|
||||
windows_updater_.Cancel();
|
||||
#endif
|
||||
ui_->main->set_update_open(false);
|
||||
});
|
||||
main->on_connection_cancel([this] {
|
||||
const auto props = FindRemoteSession(ui_->connection_dialog_remote_id);
|
||||
if (!props) {
|
||||
@@ -2100,6 +2115,9 @@ void GuiApplication::SyncMainWindow() {
|
||||
ui_->main->set_signal_tls_error(signal_status_ ==
|
||||
SignalStatus::SignalTlsCertError);
|
||||
ui_->main->set_update_available(update_available_);
|
||||
#if _WIN32
|
||||
SyncWindowsUpdate();
|
||||
#endif
|
||||
ui_->main->set_current_version(CROSSDESK_VERSION);
|
||||
ui_->main->set_latest_version(UiText(latest_version_));
|
||||
ui_->main->set_release_name(UiText(release_name_));
|
||||
@@ -3257,7 +3275,51 @@ bool GuiApplication::OpenUrl(const std::string& url) {
|
||||
return SDL_OpenURL(url.c_str());
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
void GuiApplication::SyncWindowsUpdate() {
|
||||
using State = WindowsUpdater::State;
|
||||
if (windows_updater_.GetState() == State::Ready) {
|
||||
windows_updater_.Launch();
|
||||
if (windows_updater_.GetState() == State::Launched) {
|
||||
ui_->main->set_update_open(false);
|
||||
}
|
||||
}
|
||||
const State state = windows_updater_.GetState();
|
||||
const bool downloading = state == State::Downloading;
|
||||
ui_->main->set_update_downloading(downloading || state == State::Launching);
|
||||
ui_->main->set_update_failed(state == State::Failed ||
|
||||
state == State::LaunchFailed);
|
||||
const int language = localization_language_index_;
|
||||
std::string status;
|
||||
if (downloading) {
|
||||
status = localization::update_downloading[language];
|
||||
const uint64_t total = windows_updater_.Total();
|
||||
const uint64_t received = windows_updater_.Downloaded();
|
||||
if (total > 0) {
|
||||
const int percent = static_cast<int>(std::min(100.0, 100.0 * received / total));
|
||||
status += " " + std::to_string(percent) + "%";
|
||||
ui_->main->set_update_progress(static_cast<float>(percent) / 100.0f);
|
||||
} else {
|
||||
status += " " + std::to_string(received / (1024 * 1024)) + " MB";
|
||||
ui_->main->set_update_progress(-1.0f);
|
||||
}
|
||||
} else if (state == State::Failed) {
|
||||
status = localization::update_download_failed[language];
|
||||
} else if (state == State::LaunchFailed) {
|
||||
status = localization::update_launch_failed[language];
|
||||
} else if (state == State::Launching) {
|
||||
status = localization::update_launching[language];
|
||||
} else if (state == State::Launched) {
|
||||
status = localization::update_installer_opened[language];
|
||||
}
|
||||
ui_->main->set_update_status(UiText(status));
|
||||
}
|
||||
#endif
|
||||
|
||||
void GuiApplication::Cleanup() {
|
||||
#if _WIN32
|
||||
windows_updater_.Cancel();
|
||||
#endif
|
||||
if (!ui_) {
|
||||
SDL_Quit();
|
||||
return;
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
#include "runtime/cursor_state_provider.h"
|
||||
#include "runtime/gui_runtime.h"
|
||||
#if _WIN32
|
||||
#include "platform/windows/windows_updater.h"
|
||||
#endif
|
||||
|
||||
namespace crossdesk {
|
||||
|
||||
@@ -52,6 +55,9 @@ private:
|
||||
void HandlePasswordChangeResult();
|
||||
void HandleCredentialRecovery();
|
||||
void SyncMainWindow();
|
||||
#if _WIN32
|
||||
void SyncWindowsUpdate();
|
||||
#endif
|
||||
void SyncConnectionDialog();
|
||||
void SyncPlatformDialogs();
|
||||
void SyncStreamWindow();
|
||||
@@ -87,6 +93,9 @@ private:
|
||||
bool OpenUrl(const std::string &url);
|
||||
|
||||
std::unique_ptr<SlintUi> ui_;
|
||||
#if _WIN32
|
||||
WindowsUpdater windows_updater_;
|
||||
#endif
|
||||
CursorStateProvider cursor_state_provider_;
|
||||
std::unordered_map<std::string, CursorDeliveryState>
|
||||
cursor_delivery_states_;
|
||||
@@ -100,4 +109,4 @@ private:
|
||||
|
||||
} // namespace crossdesk
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -184,6 +184,20 @@ struct TranslationRow {
|
||||
X(notification, u8"通知", "Notification", u8"Уведомление") \
|
||||
X(new_version_available, u8"新版本可用", "New Version Available", \
|
||||
u8"Доступна новая версия") \
|
||||
X(update_downloading, u8"正在下载安装包…", "Downloading installer…", \
|
||||
u8"Загрузка установщика…") \
|
||||
X(update_launching, u8"正在打开安装包,请确认管理员权限请求…", \
|
||||
"Opening installer. Please confirm the administrator permission request…", \
|
||||
u8"Запуск установщика. Подтвердите запрос прав администратора…") \
|
||||
X(update_download_failed, u8"下载失败,请点击更新重试,或访问官网。", \
|
||||
"Download failed. Click Update to retry, or visit the website.", \
|
||||
u8"Ошибка загрузки. Повторите обновление или откройте сайт.") \
|
||||
X(update_launch_failed, u8"安装包未能启动或授权已取消,请点击更新重试。", \
|
||||
"Installer launch failed or permission was cancelled. Click Update to retry.", \
|
||||
u8"Установщик не запущен или доступ отменён. Повторите обновление.") \
|
||||
X(update_installer_opened, u8"安装包已打开,请在安装向导中完成更新。", \
|
||||
"Installer opened. Follow the setup wizard to finish updating.", \
|
||||
u8"Установщик открыт. Следуйте указаниям мастера установки.") \
|
||||
X(release_notes, u8"更新内容", "Release Notes", u8"Содержание обновления") \
|
||||
X(version, u8"版本", "Version", u8"Версия") \
|
||||
X(release_date, u8"发布日期: ", "Release Date: ", u8"Дата релиза: ") \
|
||||
|
||||
@@ -210,6 +210,10 @@ export component MainWindow inherits Window {
|
||||
in property <bool> signal-tls-error: false;
|
||||
in property <[RecentConnection]> recent-connections;
|
||||
in property <bool> update-available: false;
|
||||
in property <bool> update-downloading: false;
|
||||
in property <bool> update-failed: false;
|
||||
in property <float> update-progress: 0;
|
||||
in property <string> update-status: "";
|
||||
in property <string> current-version: "";
|
||||
in property <string> latest-version: "";
|
||||
in property <string> release-name: "";
|
||||
@@ -268,6 +272,8 @@ export component MainWindow inherits Window {
|
||||
callback cancel-self-hosted-settings;
|
||||
callback browse-save-path;
|
||||
callback open-download;
|
||||
callback start-update;
|
||||
callback cancel-update;
|
||||
callback connection-cancel;
|
||||
callback connection-acknowledge;
|
||||
callback connection-submit-password(string, bool);
|
||||
@@ -1644,7 +1650,7 @@ export component MainWindow inherits Window {
|
||||
x: 30px;
|
||||
y: 105px;
|
||||
width: 360px;
|
||||
height: 190px;
|
||||
height: root.update-status != "" ? 136px : 190px;
|
||||
background: white;
|
||||
border-width: 1px;
|
||||
border-color: #b9bdc3;
|
||||
@@ -1671,8 +1677,27 @@ export component MainWindow inherits Window {
|
||||
}
|
||||
}
|
||||
}
|
||||
CompactButton { x: root.compact-language ? 163px : 130px; y: 309px; width: root.compact-language ? 34px : 70px; primary: true; text: UiStrings.download; clicked => { root.open-download(); root.update-open = false; } }
|
||||
CompactButton { x: root.compact-language ? 204px : 207px; y: 309px; width: root.compact-language ? 34px : 56px; text: UiStrings.later; clicked => { root.update-open = false; } }
|
||||
if root.update-status != "": Text {
|
||||
x: 30px; y: 247px; width: 340px; height: 40px;
|
||||
text: root.update-status;
|
||||
color: root.update-failed ? #b23b3b : #3d434d;
|
||||
font-size: ImGuiFontStyle.body;
|
||||
wrap: word-wrap;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
if root.update-downloading: Rectangle {
|
||||
x: 30px; y: 291px; width: 340px; height: 4px;
|
||||
background: #e2e4e7;
|
||||
clip: true;
|
||||
Rectangle {
|
||||
x: root.update-progress < 0 ? (parent.width + self.width) * (mod(animation-tick(), 1500ms) / 1500ms) - self.width : 0px;
|
||||
width: parent.width * (root.update-progress < 0 ? 0.25 : root.update-progress);
|
||||
height: parent.height;
|
||||
background: #334fd1;
|
||||
}
|
||||
}
|
||||
CompactButton { x: root.compact-language ? 163px : 130px; y: 309px; width: root.compact-language ? 34px : 70px; primary: true; text: UiStrings.download; enabled: !root.update-downloading; clicked => { root.start-update(); } }
|
||||
CompactButton { x: root.compact-language ? 204px : 207px; y: 309px; width: root.compact-language ? 34px : 56px; text: UiStrings.later; clicked => { root.cancel-update(); } }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user