mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-01-23 13:08:41 -06:00
impr: Better auto updater, added support for updating nightlies
This commit is contained in:
@@ -821,6 +821,7 @@ EXPORT_MODULE namespace hex {
|
||||
|
||||
struct TitleBarButton {
|
||||
std::string icon;
|
||||
ImGuiCustomCol color;
|
||||
UnlocalizedString unlocalizedTooltip;
|
||||
ClickCallback callback;
|
||||
};
|
||||
@@ -1007,11 +1008,13 @@ EXPORT_MODULE namespace hex {
|
||||
/**
|
||||
* @brief Adds a new title bar button
|
||||
* @param icon The icon to use for the button
|
||||
* @param color The color of the icon
|
||||
* @param unlocalizedTooltip The unlocalized tooltip to use for the button
|
||||
* @param function The function to call when the button is clicked
|
||||
*/
|
||||
void addTitleBarButton(
|
||||
const std::string &icon,
|
||||
ImGuiCustomCol color,
|
||||
const UnlocalizedString &unlocalizedTooltip,
|
||||
const impl::ClickCallback &function
|
||||
);
|
||||
|
||||
@@ -1071,8 +1071,8 @@ namespace hex {
|
||||
impl::s_sidebarItems->push_back({ icon, function, enabledCallback });
|
||||
}
|
||||
|
||||
void addTitleBarButton(const std::string &icon, const UnlocalizedString &unlocalizedTooltip, const impl::ClickCallback &function) {
|
||||
impl::s_titlebarButtons->push_back({ icon, unlocalizedTooltip, function });
|
||||
void addTitleBarButton(const std::string &icon, ImGuiCustomCol color, const UnlocalizedString &unlocalizedTooltip, const impl::ClickCallback &function) {
|
||||
impl::s_titlebarButtons->push_back({ icon, color, unlocalizedTooltip, function });
|
||||
}
|
||||
|
||||
void addWelcomeScreenQuickSettingsToggle(const std::string &icon, const UnlocalizedString &unlocalizedTooltip, bool defaultState, const impl::ToggleCallback &function) {
|
||||
|
||||
@@ -941,7 +941,7 @@ namespace hex {
|
||||
std::string updateTypeString;
|
||||
switch (updateType) {
|
||||
case UpdateType::Stable:
|
||||
updateTypeString = "latest";
|
||||
updateTypeString = "stable";
|
||||
break;
|
||||
case UpdateType::Nightly:
|
||||
updateTypeString = "nightly";
|
||||
|
||||
@@ -7,14 +7,11 @@
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
std::string getUpdateUrl(std::string_view versionType, std::string_view operatingSystem) {
|
||||
std::string getArtifactUrl(std::string_view artifactEnding, hex::ImHexApi::System::UpdateType updateType) {
|
||||
// Get the latest version info from the ImHex API
|
||||
const auto response = hex::HttpRequest("GET",
|
||||
ImHexApiURL + fmt::format("/update/{}/{}",
|
||||
versionType,
|
||||
operatingSystem
|
||||
)
|
||||
).execute().get();
|
||||
GitHubApiURL + "/releases"s
|
||||
).execute().get();
|
||||
|
||||
const auto &data = response.getData();
|
||||
|
||||
@@ -25,7 +22,30 @@ std::string getUpdateUrl(std::string_view versionType, std::string_view operatin
|
||||
return { };
|
||||
}
|
||||
|
||||
return data;
|
||||
try {
|
||||
const auto json = nlohmann::json::parse(data);
|
||||
|
||||
for (const auto &release : json) {
|
||||
if (updateType == hex::ImHexApi::System::UpdateType::Stable && !release["target_commitish"].get<std::string>().starts_with("releases/v"))
|
||||
continue;
|
||||
if (updateType == hex::ImHexApi::System::UpdateType::Nightly && release["tag_name"].get<std::string>() != "nightly")
|
||||
continue;
|
||||
|
||||
// Loop over all assets in the release
|
||||
for (const auto &asset : release["assets"]) {
|
||||
// Check if the asset name ends with the specified artifact ending
|
||||
if (asset["name"].get<std::string>().ends_with(artifactEnding)) {
|
||||
return asset["browser_download_url"].get<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hex::log::error("No suitable artifact found for ending: {}", artifactEnding);
|
||||
return { };
|
||||
} catch (const std::exception &e) {
|
||||
hex::log::error("Failed to parse latest version info: {}", e.what());
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::fs::path> downloadUpdate(const std::string &url) {
|
||||
@@ -40,20 +60,20 @@ std::optional<std::fs::path> downloadUpdate(const std::string &url) {
|
||||
|
||||
const auto &data = response.getData();
|
||||
|
||||
const auto updateFileName = wolv::util::splitString(url, "/").back();
|
||||
|
||||
// Write the update to a file
|
||||
std::fs::path filePath;
|
||||
{
|
||||
constexpr static auto UpdateFileName = "update.hexupd";
|
||||
|
||||
// Loop over all available paths
|
||||
wolv::io::File file;
|
||||
for (const auto &path : hex::paths::Config.write()) {
|
||||
// Remove any existing update files
|
||||
wolv::io::fs::remove(path / UpdateFileName);
|
||||
wolv::io::fs::remove(path / updateFileName);
|
||||
|
||||
// If a valid location hasn't been found already, try to create a new file
|
||||
if (!file.isValid())
|
||||
file = wolv::io::File(path / UpdateFileName, wolv::io::File::Mode::Create);
|
||||
file = wolv::io::File(path / updateFileName, wolv::io::File::Mode::Create);
|
||||
}
|
||||
|
||||
// If the update data can't be written to any of the default paths, the update cannot continue
|
||||
@@ -74,67 +94,64 @@ std::optional<std::fs::path> downloadUpdate(const std::string &url) {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
std::string getUpdateType() {
|
||||
#if defined(__x86_64__)
|
||||
#define ARCH_DEPENDENT(x86_64, arm64) x86_64
|
||||
#elif defined(__arm64__)
|
||||
#define ARCH_DEPENDENT(x86_64, arm64) arm64
|
||||
#else
|
||||
#define ARCH_DEPENDENT(x86_64, arm64) ""
|
||||
#endif
|
||||
|
||||
std::string_view getUpdateArtifactEnding() {
|
||||
#if defined (OS_WINDOWS)
|
||||
if (!hex::ImHexApi::System::isPortableVersion())
|
||||
return "win-msi";
|
||||
if (!hex::ImHexApi::System::isPortableVersion()) {
|
||||
return ARCH_DEPENDENT("Windows-x86_64.msi", "Windows-arm64.msi");
|
||||
}
|
||||
#elif defined (OS_MACOS)
|
||||
#if defined(__x86_64__)
|
||||
return "macos-dmg-x86";
|
||||
#elif defined(__arm64__)
|
||||
return "macos-dmg-arm";
|
||||
#endif
|
||||
return ARCH_DEPENDENT("macOS-x86_64.dmg", "macOS-arm64.dmg");
|
||||
#elif defined (OS_LINUX)
|
||||
if (hex::executeCommand("grep 'ID=ubuntu' /etc/os-release") == 0) {
|
||||
if (hex::executeCommand("grep 'VERSION_ID=\"24.04\"' /etc/os-release") == 0)
|
||||
return "linux-deb-24.04";
|
||||
return ARCH_DEPENDENT("Ubuntu-24.04-x86_64.deb", "");
|
||||
else if (hex::executeCommand("grep 'VERSION_ID=\"24.10\"' /etc/os-release") == 0)
|
||||
return "linux-deb-24.10";
|
||||
return ARCH_DEPENDENT("Ubuntu-24.10-x86_64.deb", "");
|
||||
else if (hex::executeCommand("grep 'VERSION_ID=\"25.04\"' /etc/os-release") == 0)
|
||||
return ARCH_DEPENDENT("Ubuntu-25.04-x86_64.deb", "");
|
||||
} else if (hex::executeCommand("grep 'ID=fedora' /etc/os-release") == 0) {
|
||||
if (hex::executeCommand("grep 'VERSION_ID=\"40\"' /etc/os-release") == 0)
|
||||
return "linux-rpm-40";
|
||||
else if (hex::executeCommand("grep 'VERSION_ID=\"41\"' /etc/os-release") == 0)
|
||||
return "linux-rpm-41";
|
||||
if (hex::executeCommand("grep 'VERSION_ID=\"41\"' /etc/os-release") == 0)
|
||||
return ARCH_DEPENDENT("Fedora-41-x86_64.rpm", "");
|
||||
else if (hex::executeCommand("grep 'VERSION_ID=\"42\"' /etc/os-release") == 0)
|
||||
return ARCH_DEPENDENT("Fedora-42-x86_64.rpm", "");
|
||||
else if (hex::executeCommand("grep 'VERSION_ID=\"rawhide\"' /etc/os-release") == 0)
|
||||
return "linux-rpm-rawhide";
|
||||
return ARCH_DEPENDENT("Fedora-rawhide-x86_64.rpm", "");
|
||||
} else if (hex::executeCommand("grep '^NAME=\"Arch Linux\"' /etc/os-release") == 0) {
|
||||
return "linux-arch";
|
||||
return ARCH_DEPENDENT("ArchLinux-x86_64.pkg.tar.zst", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
int installUpdate(const std::string &type, std::fs::path updatePath) {
|
||||
int installUpdate(const std::fs::path &updatePath) {
|
||||
struct UpdateHandler {
|
||||
const char *type;
|
||||
const char *extension;
|
||||
const char *ending;
|
||||
const char *command;
|
||||
};
|
||||
|
||||
constexpr static auto UpdateHandlers = {
|
||||
UpdateHandler { "win-msi", ".msi", "msiexec /i \"{}\" /qb" },
|
||||
UpdateHandler { "macos-dmg-x86", ".dmg", "hdiutil attach -autoopen \"{}\"" },
|
||||
UpdateHandler { "macos-dmg-arm", ".dmg", "hdiutil attach -autoopen \"{}\"" },
|
||||
UpdateHandler { "linux-deb-24.04", ".deb", "sudo apt update && sudo apt install -y --fix-broken \"{}\"" },
|
||||
UpdateHandler { "linux-deb-24.10", ".deb", "sudo apt update && sudo apt install -y --fix-broken \"{}\"" },
|
||||
UpdateHandler { "linux-rpm-40", ".rpm", "sudo rpm -i \"{}\"" },
|
||||
UpdateHandler { "linux-rpm-41", ".rpm", "sudo rpm -i \"{}\"" },
|
||||
UpdateHandler { "linux-rpm-rawhide", ".rpm", "sudo rpm -i \"{}\"" },
|
||||
UpdateHandler { "linux-arch", ".zst", "sudo pacman -Syy && sudo pacman -U --noconfirm \"{}\"" }
|
||||
UpdateHandler { ".msi", "msiexec /i \"{}\" /qb" },
|
||||
UpdateHandler { ".dmg", "hdiutil attach -autoopen \"{}\"" },
|
||||
UpdateHandler { ".deb", "sudo apt update && sudo apt install -y --fix-broken \"{}\"" },
|
||||
UpdateHandler { ".rpm", "sudo rpm -i \"{}\"" },
|
||||
UpdateHandler { ".pkg.tar.zst", "sudo pacman -Syy && sudo pacman -U --noconfirm \"{}\"" }
|
||||
};
|
||||
|
||||
const auto updateFileName = wolv::util::toUTF8String(updatePath.filename());
|
||||
for (const auto &handler : UpdateHandlers) {
|
||||
if (type == handler.type) {
|
||||
// Rename the update file to the correct extension
|
||||
const auto originalPath = updatePath;
|
||||
updatePath.replace_extension(handler.extension);
|
||||
|
||||
hex::log::info("Moving update package from {} to {}", originalPath.string(), updatePath.string());
|
||||
std::fs::rename(originalPath, updatePath);
|
||||
|
||||
if (updateFileName.ends_with(handler.ending)) {
|
||||
// Install the update using the correct command
|
||||
const auto command = fmt::format(fmt::runtime(handler.command), updatePath.string());
|
||||
|
||||
hex::log::info("Starting update process with command: '{}'", command);
|
||||
hex::startProgram(command);
|
||||
|
||||
@@ -152,6 +169,8 @@ int installUpdate(const std::string &type, std::fs::path updatePath) {
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
hex::TaskManager::setCurrentThreadName("ImHex Updater");
|
||||
hex::TaskManager::setMainThreadId(std::this_thread::get_id());
|
||||
hex::log::impl::enableColorPrinting();
|
||||
|
||||
// Check we have the correct number of arguments
|
||||
@@ -161,35 +180,50 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
// Read the version type from the arguments
|
||||
const auto versionType = argv[1];
|
||||
hex::log::info("Updater started with version type: {}", versionType);
|
||||
const std::string_view versionTypeString = argv[1];
|
||||
hex::log::info("Updater started with version type: {}", versionTypeString);
|
||||
|
||||
// Query the update type
|
||||
const auto updateType = getUpdateType();
|
||||
hex::log::info("Detected OS String: {}", updateType);
|
||||
|
||||
// Make sure we got a valid update type
|
||||
if (updateType.empty()) {
|
||||
hex::log::error("Failed to detect installation type");
|
||||
// Convert the version type string to the enum value
|
||||
hex::ImHexApi::System::UpdateType updateType;
|
||||
if (versionTypeString == "stable") {
|
||||
updateType = hex::ImHexApi::System::UpdateType::Stable;
|
||||
} else if (versionTypeString == "nightly") {
|
||||
updateType = hex::ImHexApi::System::UpdateType::Nightly;
|
||||
} else {
|
||||
hex::log::error("Invalid version type: {}", versionTypeString);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Get the url to the requested update from the ImHex API
|
||||
const auto updateUrl = getUpdateUrl(versionType, updateType);
|
||||
if (updateUrl.empty()) {
|
||||
hex::log::error("Failed to get update URL");
|
||||
// Get the artifact name ending based on the current platform and architecture
|
||||
const auto artifactEnding = getUpdateArtifactEnding();
|
||||
if (artifactEnding.empty()) {
|
||||
hex::log::error("Updater artifact ending is empty");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
hex::log::info("Update URL found: {}", updateUrl);
|
||||
// Get the URL for the correct update artifact
|
||||
const auto updateArtifactUrl = getArtifactUrl(artifactEnding, updateType);
|
||||
if (updateArtifactUrl.empty()) {
|
||||
// If the current artifact cannot be updated, open the latest release page in the browser
|
||||
|
||||
hex::log::warn("Failed to get update artifact URL for ending: {}", artifactEnding);
|
||||
hex::log::info("Opening release page in browser to allow manual update");
|
||||
|
||||
switch (updateType) {
|
||||
case hex::ImHexApi::System::UpdateType::Stable:
|
||||
hex::openWebpage("https://github.com/WerWolv/ImHex/releases/latest");
|
||||
break;
|
||||
case hex::ImHexApi::System::UpdateType::Nightly:
|
||||
hex::openWebpage("https://github.com/WerWolv/ImHex/releases/tag/nightly");
|
||||
break;
|
||||
}
|
||||
|
||||
// Download the update file
|
||||
const auto updatePath = downloadUpdate(updateUrl);
|
||||
if (!updatePath.has_value())
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
hex::log::info("Downloaded update successfully");
|
||||
// Download the update artifact
|
||||
const auto updatePath = downloadUpdate(updateArtifactUrl);
|
||||
|
||||
// Install the update
|
||||
return installUpdate(updateType, *updatePath);
|
||||
return installUpdate(*updatePath);
|
||||
}
|
||||
@@ -21,76 +21,122 @@ namespace hex::plugin::builtin {
|
||||
int checkForUpdates = ContentRegistry::Settings::read<int>("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 2);
|
||||
|
||||
// Check if we should check for updates
|
||||
if (checkForUpdates == 1) {
|
||||
HttpRequest request("GET", GitHubApiURL + "/releases/latest"s);
|
||||
TaskManager::createBackgroundTask("Update Check", [checkForUpdates] {
|
||||
std::string updateString;
|
||||
if (checkForUpdates == 1) {
|
||||
if (ImHexApi::System::isNightlyBuild()) {
|
||||
HttpRequest request("GET", GitHubApiURL + "/releases/tags/nightly"s);
|
||||
request.setTimeout(10000);
|
||||
|
||||
// Query the GitHub API for the latest release version
|
||||
auto response = request.execute().get();
|
||||
if (response.getStatusCode() != 200)
|
||||
return false;
|
||||
// Query the GitHub API for the latest release version
|
||||
auto response = request.execute().get();
|
||||
if (response.getStatusCode() != 200)
|
||||
return;
|
||||
|
||||
nlohmann::json releases;
|
||||
try {
|
||||
releases = nlohmann::json::parse(response.getData());
|
||||
} catch (const std::exception &) {
|
||||
return false;
|
||||
nlohmann::json releases;
|
||||
try {
|
||||
releases = nlohmann::json::parse(response.getData());
|
||||
} catch (const std::exception &) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the response is valid
|
||||
if (!releases.contains("published_at") || !releases["published_at"].is_string())
|
||||
return;
|
||||
|
||||
std::chrono::system_clock::time_point nightlyUpdateTime;
|
||||
{
|
||||
std::istringstream iss(releases["published_at"].get<std::string>());
|
||||
iss >> std::chrono::parse("%FT%TZ", nightlyUpdateTime);
|
||||
}
|
||||
|
||||
if (nightlyUpdateTime > std::chrono::system_clock::now()) {
|
||||
updateString = "Nightly";
|
||||
}
|
||||
} else {
|
||||
HttpRequest request("GET", GitHubApiURL + "/releases/latest"s);
|
||||
|
||||
// Query the GitHub API for the latest release version
|
||||
auto response = request.execute().get();
|
||||
if (response.getStatusCode() != 200)
|
||||
return;
|
||||
|
||||
nlohmann::json releases;
|
||||
try {
|
||||
releases = nlohmann::json::parse(response.getData());
|
||||
} catch (const std::exception &) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the response is valid
|
||||
if (!releases.contains("tag_name") || !releases["tag_name"].is_string())
|
||||
return;
|
||||
|
||||
// Convert the current version string to a format that can be compared to the latest release
|
||||
auto currVersion = "v" + ImHexApi::System::getImHexVersion().get(false);
|
||||
|
||||
// Get the latest release version string
|
||||
auto latestVersion = releases["tag_name"].get<std::string_view>();
|
||||
|
||||
// Check if the latest release is different from the current version
|
||||
if (latestVersion != currVersion)
|
||||
updateString = latestVersion;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the response is valid
|
||||
if (!releases.contains("tag_name") || !releases["tag_name"].is_string())
|
||||
return false;
|
||||
if (updateString.empty())
|
||||
return;
|
||||
|
||||
// Convert the current version string to a format that can be compared to the latest release
|
||||
auto currVersion = "v" + ImHexApi::System::getImHexVersion().get(false);
|
||||
TaskManager::doLater([updateString] {
|
||||
ContentRegistry::Interface::addTitleBarButton(ICON_VS_ARROW_DOWN, ImGuiCustomCol_ToolbarGreen, "hex.builtin.welcome.update.title", [] {
|
||||
ImHexApi::System::updateImHex(ImHexApi::System::isNightlyBuild() ? ImHexApi::System::UpdateType::Nightly : ImHexApi::System::UpdateType::Stable);
|
||||
});
|
||||
|
||||
// Get the latest release version string
|
||||
auto latestVersion = releases["tag_name"].get<std::string_view>();
|
||||
|
||||
// Check if the latest release is different from the current version
|
||||
if (latestVersion != currVersion)
|
||||
ImHexApi::System::impl::addInitArgument("update-available", latestVersion.data());
|
||||
|
||||
// Check if there is a telemetry uuid
|
||||
auto uuid = ContentRegistry::Settings::read<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", "");
|
||||
if (uuid.empty()) {
|
||||
// Generate a new uuid
|
||||
uuid = wolv::hash::generateUUID();
|
||||
// Save
|
||||
ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", uuid);
|
||||
}
|
||||
|
||||
TaskManager::createBackgroundTask("hex.builtin.task.sending_statistics", [uuid](auto&) {
|
||||
// To avoid potentially flooding our database with lots of dead users
|
||||
// from people just visiting the website, don't send telemetry data from
|
||||
// the web version
|
||||
#if defined(OS_WEB)
|
||||
return;
|
||||
#endif
|
||||
|
||||
// Make telemetry request
|
||||
nlohmann::json telemetry = {
|
||||
{ "uuid", uuid },
|
||||
{ "format_version", "1" },
|
||||
{ "imhex_version", ImHexApi::System::getImHexVersion().get(false) },
|
||||
{ "imhex_commit", fmt::format("{}@{}", ImHexApi::System::getCommitHash(true), ImHexApi::System::getCommitBranch()) },
|
||||
{ "install_type", ImHexApi::System::isPortableVersion() ? "Portable" : "Installed" },
|
||||
{ "os", ImHexApi::System::getOSName() },
|
||||
{ "os_version", ImHexApi::System::getOSVersion() },
|
||||
{ "arch", ImHexApi::System::getArchitecture() },
|
||||
{ "gpu_vendor", ImHexApi::System::getGPUVendor() },
|
||||
{ "corporate_env", ImHexApi::System::isCorporateEnvironment() }
|
||||
};
|
||||
|
||||
HttpRequest telemetryRequest("POST", ImHexApiURL + "/telemetry"s);
|
||||
telemetryRequest.setTimeout(500);
|
||||
|
||||
telemetryRequest.setBody(telemetry.dump());
|
||||
telemetryRequest.addHeader("Content-Type", "application/json");
|
||||
|
||||
// Execute request
|
||||
telemetryRequest.execute();
|
||||
ui::ToastInfo::open(fmt::format("hex.builtin.welcome.update.desc"_lang, updateString));
|
||||
});
|
||||
});
|
||||
|
||||
// Check if there is a telemetry uuid
|
||||
auto uuid = ContentRegistry::Settings::read<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", "");
|
||||
if (uuid.empty()) {
|
||||
// Generate a new uuid
|
||||
uuid = wolv::hash::generateUUID();
|
||||
// Save
|
||||
ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", uuid);
|
||||
}
|
||||
|
||||
TaskManager::createBackgroundTask("hex.builtin.task.sending_statistics", [uuid](auto&) {
|
||||
// To avoid potentially flooding our database with lots of dead users
|
||||
// from people just visiting the website, don't send telemetry data from
|
||||
// the web version
|
||||
#if defined(OS_WEB)
|
||||
return;
|
||||
#endif
|
||||
|
||||
// Make telemetry request
|
||||
nlohmann::json telemetry = {
|
||||
{ "uuid", uuid },
|
||||
{ "format_version", "1" },
|
||||
{ "imhex_version", ImHexApi::System::getImHexVersion().get(false) },
|
||||
{ "imhex_commit", fmt::format("{}@{}", ImHexApi::System::getCommitHash(true), ImHexApi::System::getCommitBranch()) },
|
||||
{ "install_type", ImHexApi::System::isPortableVersion() ? "Portable" : "Installed" },
|
||||
{ "os", ImHexApi::System::getOSName() },
|
||||
{ "os_version", ImHexApi::System::getOSVersion() },
|
||||
{ "arch", ImHexApi::System::getArchitecture() },
|
||||
{ "gpu_vendor", ImHexApi::System::getGPUVendor() },
|
||||
{ "corporate_env", ImHexApi::System::isCorporateEnvironment() }
|
||||
};
|
||||
|
||||
HttpRequest telemetryRequest("POST", ImHexApiURL + "/telemetry"s);
|
||||
telemetryRequest.setTimeout(500);
|
||||
|
||||
telemetryRequest.setBody(telemetry.dump());
|
||||
telemetryRequest.addHeader("Content-Type", "application/json");
|
||||
|
||||
// Execute request
|
||||
telemetryRequest.execute();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
void addTitleBarButtons() {
|
||||
if (dbg::debugModeEnabled()) {
|
||||
ContentRegistry::Interface::addTitleBarButton(ICON_VS_DEBUG, "hex.builtin.title_bar_button.debug_build", []{
|
||||
ContentRegistry::Interface::addTitleBarButton(ICON_VS_DEBUG, ImGuiCustomCol_ToolbarGray, "hex.builtin.title_bar_button.debug_build", []{
|
||||
if (ImGui::GetIO().KeyShift) {
|
||||
RequestOpenPopup::post("DebugMenu");
|
||||
} else {
|
||||
@@ -37,7 +37,7 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
}
|
||||
|
||||
ContentRegistry::Interface::addTitleBarButton(ICON_VS_SMILEY, "hex.builtin.title_bar_button.feedback", []{
|
||||
ContentRegistry::Interface::addTitleBarButton(ICON_VS_SMILEY, ImGuiCustomCol_ToolbarGray, "hex.builtin.title_bar_button.feedback", []{
|
||||
hex::openWebpage("https://github.com/WerWolv/ImHex/discussions/categories/feedback");
|
||||
});
|
||||
|
||||
@@ -555,15 +555,6 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::Interface::addMenuItemToToolbar("hex.builtin.view.hex_editor.menu.file.save", ImGuiCustomCol_ToolbarBlue);
|
||||
ContentRegistry::Interface::addMenuItemToToolbar("hex.builtin.view.hex_editor.menu.file.save_as", ImGuiCustomCol_ToolbarBlue);
|
||||
ContentRegistry::Interface::addMenuItemToToolbar("hex.builtin.menu.edit.bookmark.create", ImGuiCustomCol_ToolbarGreen);
|
||||
|
||||
const auto &initArgs = ImHexApi::System::getInitArguments();
|
||||
if (auto it = initArgs.find("update-available"); it != initArgs.end()) {
|
||||
ContentRegistry::Interface::addTitleBarButton(ICON_VS_GIFT, "hex.builtin.welcome.update.title", [] {
|
||||
ImHexApi::System::updateImHex(ImHexApi::System::UpdateType::Stable);
|
||||
});
|
||||
|
||||
ui::ToastInfo::open(fmt::format("hex.builtin.welcome.update.desc"_lang, it->second));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -232,18 +232,20 @@ namespace hex::plugin::builtin {
|
||||
#endif
|
||||
}
|
||||
|
||||
auto &titleBarButtons = ContentRegistry::Interface::impl::getTitlebarButtons();
|
||||
const auto &titleBarButtons = ContentRegistry::Interface::impl::getTitlebarButtons();
|
||||
|
||||
// Draw custom title bar buttons
|
||||
if (!titleBarButtons.empty()) {
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 7_scaled - (buttonSize.x + ImGui::GetStyle().ItemSpacing.x) * float((titleBarButtonsVisible ? 4 : 0) + titleBarButtons.size()));
|
||||
|
||||
if (ImGui::GetCursorPosX() > (searchBoxPos.x + searchBoxSize.x)) {
|
||||
for (const auto &[icon, tooltip, callback] : titleBarButtons) {
|
||||
for (const auto &[icon, color, tooltip, callback] : titleBarButtons) {
|
||||
ImGui::SetCursorPosY(titleBarButtonPosY);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiExt::GetCustomColorVec4(color));
|
||||
if (ImGuiExt::TitleBarButton(icon.c_str(), buttonSize)) {
|
||||
callback();
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGuiExt::InfoTooltip(Lang(tooltip));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user