From 5cb085b00caa96edb9cb4f9d5ec4ee4c6aff03e8 Mon Sep 17 00:00:00 2001 From: niklascfw Date: Sun, 17 May 2026 12:59:14 +0200 Subject: [PATCH] daybreak: Add firmware compatibility gate and German UI Block unsupported firmware updates via a dedicated dialog using Exosphere's maximum supported HOS version, and translate the Daybreak interface to German. --- troposphere/daybreak/source/ui.cpp | 225 ++++++++++++++++-------- troposphere/daybreak/source/ui.hpp | 11 ++ troposphere/daybreak/source/ui_util.cpp | 2 +- 3 files changed, 166 insertions(+), 72 deletions(-) diff --git a/troposphere/daybreak/source/ui.cpp b/troposphere/daybreak/source/ui.cpp index 1e63f8811..7afd444e6 100644 --- a/troposphere/daybreak/source/ui.cpp +++ b/troposphere/daybreak/source/ui.cpp @@ -141,8 +141,31 @@ namespace dbk { return rc; } - u32 EncodeVersion(u32 major, u32 minor, u32 micro, u32 relstep = 0) { - return ((major & 0xFF) << 24) | ((minor & 0xFF) << 16) | ((micro & 0xFF) << 8) | ((relstep & 0xFF) << 8); + u32 EncodeVersion(u32 major, u32 minor, u32 micro) { + return ((major & 0xFF) << 24) | ((minor & 0xFF) << 16) | ((micro & 0xFF) << 8); + } + + u32 NcmVersionToHosVersion(u32 ncm_version) { + const u32 major = (ncm_version >> 26) & 0x1f; + const u32 minor = (ncm_version >> 20) & 0x1f; + const u32 micro = (ncm_version >> 16) & 0xf; + return EncodeVersion(major, minor, micro); + } + + bool IsHosVersionSupported(u32 hos_version) { + return hos_version <= g_supported_version; + } + + std::shared_ptr CreateUpdateMenuAfterPathSelection(std::shared_ptr prev_menu) { + AmsSuUpdateInformation update_info = {}; + if (R_SUCCEEDED(amssuGetUpdateInformation(&update_info, g_update_path))) { + const u32 update_hos_version = NcmVersionToHosVersion(update_info.version); + if (!IsHosVersionSupported(update_hos_version)) { + return std::make_shared(prev_menu, update_info.version, g_supported_version); + } + } + + return std::make_shared(prev_menu); } } @@ -347,7 +370,7 @@ namespace dbk { /* Copy result text if there is a result. */ if (R_FAILED(rc)) { - snprintf(m_result_text, sizeof(m_result_text), "Result: 0x%08x", rc); + snprintf(m_result_text, sizeof(m_result_text), "Ergebnis: 0x%08x", rc); } } @@ -375,7 +398,7 @@ namespace dbk { const float button_width = WindowWidth - HorizontalInset * 2.0f; /* Add buttons. */ - this->AddButton(ExitButtonId, "Exit", x + HorizontalInset, button_y, button_width, ButtonHeight); + this->AddButton(ExitButtonId, "Beenden", x + HorizontalInset, button_y, button_width, ButtonHeight); this->SetButtonSelected(ExitButtonId, true); } @@ -412,8 +435,8 @@ namespace dbk { const float button_y = y + TitleGap + SubTextHeight + VerticalGap * 2.0f + (R_FAILED(m_rc) ? SubTextHeight : 0.0f); const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap; - this->AddButton(BackButtonId, "Back", x + HorizontalInset, button_y, button_width, ButtonHeight); - this->AddButton(ContinueButtonId, "Continue", x + HorizontalInset + button_width + ButtonHorizontalGap, button_y, button_width, ButtonHeight); + this->AddButton(BackButtonId, "Zurück", x + HorizontalInset, button_y, button_width, ButtonHeight); + this->AddButton(ContinueButtonId, "Weiter", x + HorizontalInset + button_width + ButtonHorizontalGap, button_y, button_width, ButtonHeight); this->SetButtonSelected(ContinueButtonId, true); } @@ -446,12 +469,75 @@ namespace dbk { } } + namespace { + + struct FirmwareNotSupportedSubtext { + char value[0x100]; + + FirmwareNotSupportedSubtext(u32 update_ncm_version, u32 max_supported_hos_version) { + snprintf(this->value, sizeof(this->value), + "Maximal unterstützte Firmware ist %u.%u.%u.\n" + "Aktualisiere Atmosphere, bevor du diese Firmware installierst.", + (max_supported_hos_version >> 24) & 0xff, (max_supported_hos_version >> 16) & 0xff, (max_supported_hos_version >> 8) & 0xff); + } + + operator const char *() const { + return this->value; + } + }; + + } + + FirmwareNotSupportedMenu::FirmwareNotSupportedMenu(std::shared_ptr prev_menu, u32 update_ncm_version, u32 max_supported_hos_version) + : AlertMenu(prev_menu, "Nicht unterstützte Firmware-Version", FirmwareNotSupportedSubtext(update_ncm_version, max_supported_hos_version), 0) { + const float window_height = WindowHeight + SubTextAreaHeight; + const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; + const float y = g_screen_height / 2.0f - window_height / 2.0f; + const float button_y = y + TitleGap + SubTextAreaHeight + VerticalGap * 2.0f; + const float button_width = WindowWidth - HorizontalInset * 2.0f; + + this->AddButton(BackButtonId, "Zurück", x + HorizontalInset, button_y, button_width, ButtonHeight); + this->SetButtonSelected(BackButtonId, true); + } + + void FirmwareNotSupportedMenu::Draw(NVGcontext *vg, u64 ns) { + const float window_height = WindowHeight + SubTextAreaHeight; + const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; + const float y = g_screen_height / 2.0f - window_height / 2.0f; + + DrawWindow(vg, m_text, x, y, WindowWidth, window_height); + DrawTextBlock(vg, m_subtext, x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2.0f, SubTextAreaHeight); + this->DrawButtons(vg, ns); + } + + void FirmwareNotSupportedMenu::Update(u64 ns) { + u64 k_down = padGetButtonsDown(&g_pad); + + if (k_down & HidNpadButton_B) { + ReturnToPreviousMenu(); + return; + } + + if (const Button *activated_button = this->GetActivatedButton(); activated_button != nullptr) { + if (activated_button->id == BackButtonId) { + ReturnToPreviousMenu(); + return; + } + } + + this->UpdateButtons(); + + if (const Button *selected_button = this->GetSelectedButton(); k_down && selected_button == nullptr) { + this->SetButtonSelected(BackButtonId, true); + } + } + MainMenu::MainMenu() : Menu(nullptr) { const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; - this->AddButton(InstallButtonId, "Install", x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2, ButtonHeight); - this->AddButton(ExitButtonId, "Exit", x + HorizontalInset, y + TitleGap + ButtonHeight + VerticalGap, WindowWidth - HorizontalInset * 2, ButtonHeight); + this->AddButton(InstallButtonId, "Installieren", x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2, ButtonHeight); + this->AddButton(ExitButtonId, "Beenden", x + HorizontalInset, y + TitleGap + ButtonHeight + VerticalGap, WindowWidth - HorizontalInset * 2, ButtonHeight); this->SetButtonSelected(InstallButtonId, true); } @@ -475,24 +561,24 @@ namespace dbk { u64 is_emummc; if (R_FAILED(rc = splGetConfig(SplConfigItem_HardwareType, &hardware_type))) { - ChangeMenu(std::make_shared("An error has occurred", "Failed to get hardware type.", rc)); + ChangeMenu(std::make_shared("Ein Fehler ist aufgetreten", "Hardwaretyp konnte nicht ermittelt werden.", rc)); return; } if (R_FAILED(rc = splGetConfig(static_cast(ExosphereHasRcmBugPatch), &has_rcm_bug_patch))) { - ChangeMenu(std::make_shared("An error has occurred", "Failed to check RCM bug status.", rc)); + ChangeMenu(std::make_shared("Ein Fehler ist aufgetreten", "RCM-Bug-Status konnte nicht geprüft werden.", rc)); return; } if (R_FAILED(rc = splGetConfig(static_cast(ExosphereEmummcType), &is_emummc))) { - ChangeMenu(std::make_shared("An error has occurred", "Failed to check emuMMC status.", rc)); + ChangeMenu(std::make_shared("Ein Fehler ist aufgetreten", "emuMMC-Status konnte nicht geprüft werden.", rc)); return; } /* Warn if we're working with a patched unit. */ const bool is_erista = hardware_type == 0 || hardware_type == 1; if (is_erista && has_rcm_bug_patch && !is_emummc) { - ChangeMenu(std::make_shared(g_current_menu, file_menu, "Warning: Patched unit detected", "You may burn fuses or render your switch inoperable.")); + ChangeMenu(std::make_shared(g_current_menu, file_menu, "Warnung: Gepatchte Konsole erkannt", "Sicherungen können durchgebrannt werden oder die Konsole unbrauchbar gemacht werden.")); } else { ChangeMenu(file_menu); } @@ -688,7 +774,7 @@ namespace dbk { snprintf(g_update_path, sizeof(g_update_path), "%s", current_path); /* Change the menu. */ - ChangeMenu(std::make_shared(g_current_menu)); + ChangeMenu(CreateUpdateMenuAfterPathSelection(g_current_menu)); } else { ChangeMenu(std::make_shared(g_current_menu, current_path)); } @@ -739,7 +825,7 @@ namespace dbk { const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; - DrawWindow(vg, "Select an update directory", x, y, WindowWidth, WindowHeight); + DrawWindow(vg, "Update-Ordner auswählen", x, y, WindowWidth, WindowHeight); DrawTextBackground(vg, x + TextBackgroundOffset, y + TitleGap, WindowWidth - TextBackgroundOffset * 2.0f, (FileRowHeight + FileRowGap) * MaxFileRows + FileRowGap); nvgSave(vg); @@ -765,8 +851,8 @@ namespace dbk { const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap; /* Add buttons. */ - this->AddButton(BackButtonId, "Back", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); - this->AddButton(ContinueButtonId, "Continue", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); + this->AddButton(BackButtonId, "Zurück", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); + this->AddButton(ContinueButtonId, "Weiter", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); this->SetButtonEnabled(BackButtonId, false); this->SetButtonEnabled(ContinueButtonId, false); @@ -776,32 +862,33 @@ namespace dbk { this->SetButtonSelected(BackButtonId, true); } else { /* Log this early so it is printed out before validation causes stalling. */ - this->LogText("Validating update, this may take a moment...\n"); + this->LogText("Update wird geprüft, bitte warten...\n"); } } Result ValidateUpdateMenu::GetUpdateInformation() { Result rc = 0; - this->LogText("Directory %s\n", g_update_path); + this->LogText("Verzeichnis %s\n", g_update_path); /* Attempt to get the update information. */ if (R_FAILED(rc = amssuGetUpdateInformation(&m_update_info, g_update_path))) { if (rc == 0x1a405) { - this->LogText("No update found in folder.\nEnsure your ncas are named correctly!\nResult: 0x%08x\n", rc); + this->LogText("Kein Update im Ordner gefunden.\nStelle sicher, dass die NCAs korrekt benannt sind!\nErgebnis: 0x%08x\n", rc); } else { - this->LogText("Failed to get update information.\nResult: 0x%08x\n", rc); + this->LogText("Update-Informationen konnten nicht abgerufen werden.\nErgebnis: 0x%08x\n", rc); } return rc; } /* Print update information. */ this->LogText("- Version: %d.%d.%d\n", (m_update_info.version >> 26) & 0x1f, (m_update_info.version >> 20) & 0x1f, (m_update_info.version >> 16) & 0xf); + this->LogText("- Von Atmosphere max. unterstützt: %d.%d.%d\n", (g_supported_version >> 24) & 0xff, (g_supported_version >> 16) & 0xff, (g_supported_version >> 8) & 0xff); if (m_update_info.exfat_supported) { - this->LogText("- exFAT: Supported\n"); + this->LogText("- exFAT: Unterstützt\n"); } else { - this->LogText("- exFAT: Unsupported\n"); + this->LogText("- exFAT: Nicht unterstützt\n"); } - this->LogText("- Firmware variations: %d\n", m_update_info.num_firmware_variations); + this->LogText("- Firmware-Varianten: %d\n", m_update_info.num_firmware_variations); /* Mark as having obtained update info. */ m_has_info = true; @@ -813,21 +900,21 @@ namespace dbk { /* Validate the update. */ if (R_FAILED(rc = amssuValidateUpdate(&m_validation_info, g_update_path))) { - this->LogText("Failed to validate update.\nResult: 0x%08x\n", rc); + this->LogText("Update konnte nicht validiert werden.\nErgebnis: 0x%08x\n", rc); return; } /* Check the result. */ if (R_SUCCEEDED(m_validation_info.result)) { - this->LogText("Update is valid!\n"); + this->LogText("Update ist gültig!\n"); if (R_FAILED(m_validation_info.exfat_result)) { const u32 version = m_validation_info.invalid_key.version; - this->LogText("exFAT Validation failed with result: 0x%08x\n", m_validation_info.exfat_result); - this->LogText("Missing content:\n- Program id: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf); + this->LogText("exFAT-Validierung fehlgeschlagen, Ergebnis: 0x%08x\n", m_validation_info.exfat_result); + this->LogText("Fehlender Inhalt:\n- Programm-ID: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf); /* Log the missing content id. */ - this->LogText("- Content id: "); + this->LogText("- Inhalts-ID: "); for (size_t i = 0; i < sizeof(NcmContentId); i++) { this->LogText("%02x", m_validation_info.invalid_content_id.c[i]); } @@ -841,11 +928,11 @@ namespace dbk { } else { /* Log the missing content info. */ const u32 version = m_validation_info.invalid_key.version; - this->LogText("Validation failed with result: 0x%08x\n", m_validation_info.result); - this->LogText("Missing content:\n- Program id: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf); + this->LogText("Validierung fehlgeschlagen, Ergebnis: 0x%08x\n", m_validation_info.result); + this->LogText("Fehlender Inhalt:\n- Programm-ID: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf); /* Log the missing content id. */ - this->LogText("- Content id: "); + this->LogText("- Inhalts-ID: "); for (size_t i = 0; i < sizeof(NcmContentId); i++) { this->LogText("%02x", m_validation_info.invalid_content_id.c[i]); } @@ -897,13 +984,7 @@ namespace dbk { /* Warn the user if they're updating with exFAT supposed to be supported but not present/corrupted. */ if (m_update_info.exfat_supported && R_FAILED(m_validation_info.exfat_result)) { - next_menu = std::make_shared(g_current_menu, next_menu, "Warning: exFAT firmware is missing or corrupt", "Are you sure you want to proceed?"); - } - - /* Warn the user if they're updating to a version higher than supported. */ - const u32 version = m_validation_info.invalid_key.version; - if (EncodeVersion((version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf) > g_supported_version) { - next_menu = std::make_shared(g_current_menu, next_menu, "Warning: firmware is too new and not known to be supported", "Are you sure you want to proceed?"); + next_menu = std::make_shared(g_current_menu, next_menu, "Warnung: exFAT-Firmware fehlt oder ist beschädigt", "Möchtest du wirklich fortfahren?"); } /* Change to the next menu. */ @@ -919,7 +1000,7 @@ namespace dbk { const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; - DrawWindow(vg, "Update information", x, y, WindowWidth, WindowHeight); + DrawWindow(vg, "Update-Informationen", x, y, WindowWidth, WindowHeight); DrawTextBackground(vg, x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2.0f, TextAreaHeight); DrawTextBlock(vg, m_log_buffer, x + HorizontalInset + TextHorizontalInset, y + TitleGap + TextVerticalInset, WindowWidth - (HorizontalInset + TextHorizontalInset) * 2.0f, TextAreaHeight - TextVerticalInset * 2.0f); @@ -933,8 +1014,8 @@ namespace dbk { const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap; /* Add buttons. */ - this->AddButton(ResetToFactorySettingsButtonId, "Reset to factory settings", x + HorizontalInset, y + TitleGap, button_width, ButtonHeight); - this->AddButton(PreserveSettingsButtonId, "Preserve settings", x + HorizontalInset + button_width + ButtonHorizontalGap, y + TitleGap, button_width, ButtonHeight); + this->AddButton(ResetToFactorySettingsButtonId, "Werkseinstellungen", x + HorizontalInset, y + TitleGap, button_width, ButtonHeight); + this->AddButton(PreserveSettingsButtonId, "Einstellungen behalten", x + HorizontalInset + button_width + ButtonHorizontalGap, y + TitleGap, button_width, ButtonHeight); this->SetButtonSelected(PreserveSettingsButtonId, true); } @@ -963,11 +1044,11 @@ namespace dbk { if (g_exfat_supported) { next_menu = std::make_shared(g_current_menu); } else { - next_menu = std::make_shared(g_current_menu, std::make_shared(g_current_menu), "Ready to begin update installation", "Are you sure you want to proceed?"); + next_menu = std::make_shared(g_current_menu, std::make_shared(g_current_menu), "Bereit zur Update-Installation", "Möchtest du wirklich fortfahren?"); } if (g_reset_to_factory) { - ChangeMenu(std::make_shared(g_current_menu, next_menu, "Warning: Factory reset selected", "Saves and installed games will be permanently deleted.")); + ChangeMenu(std::make_shared(g_current_menu, next_menu, "Warnung: Werkseinstellungen ausgewählt", "Spielstände und installierte Spiele werden dauerhaft gelöscht.")); } else { ChangeMenu(next_menu); } @@ -985,7 +1066,7 @@ namespace dbk { const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; - DrawWindow(vg, "Select settings mode", x, y, WindowWidth, WindowHeight); + DrawWindow(vg, "Einstellungsmodus wählen", x, y, WindowWidth, WindowHeight); this->DrawButtons(vg, ns); } @@ -1029,7 +1110,7 @@ namespace dbk { break; } - ChangeMenu(std::make_shared(g_current_menu, std::make_shared(g_current_menu), "Ready to begin update installation", "Are you sure you want to proceed?")); + ChangeMenu(std::make_shared(g_current_menu, std::make_shared(g_current_menu), "Bereit zur Update-Installation", "Möchtest du wirklich fortfahren?")); } this->UpdateButtons(); @@ -1044,7 +1125,7 @@ namespace dbk { const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; - DrawWindow(vg, "Select driver variant", x, y, WindowWidth, WindowHeight); + DrawWindow(vg, "Treibervariante wählen", x, y, WindowWidth, WindowHeight); this->DrawButtons(vg, ns); } @@ -1054,8 +1135,8 @@ namespace dbk { const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap; /* Add buttons. */ - this->AddButton(ShutdownButtonId, "Shutdown", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); - this->AddButton(RebootButtonId, "Reboot", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); + this->AddButton(ShutdownButtonId, "Ausschalten", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); + this->AddButton(RebootButtonId, "Neustart", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); this->SetButtonEnabled(ShutdownButtonId, false); this->SetButtonEnabled(RebootButtonId, false); @@ -1075,34 +1156,34 @@ namespace dbk { if (m_install_state == InstallState::NeedsSetup) { /* Setup the update. */ if (R_FAILED(rc = amssuSetupUpdate(nullptr, UpdateTaskBufferSize, g_update_path, g_use_exfat))) { - this->LogText("Failed to setup update.\nResult: 0x%08x\n", rc); + this->LogText("Update-Einrichtung fehlgeschlagen.\nErgebnis: 0x%08x\n", rc); this->MarkForReboot(); return rc; } /* Log setup completion. */ - this->LogText("Update setup complete.\n"); + this->LogText("Update-Einrichtung abgeschlossen.\n"); m_install_state = InstallState::NeedsPrepare; } else if (m_install_state == InstallState::NeedsPrepare) { /* Request update preparation. */ if (R_FAILED(rc = amssuRequestPrepareUpdate(&m_prepare_result))) { - this->LogText("Failed to request update preparation.\nResult: 0x%08x\n", rc); + this->LogText("Update-Vorbereitung konnte nicht angefordert werden.\nErgebnis: 0x%08x\n", rc); this->MarkForReboot(); return rc; } /* Log awaiting prepare. */ - this->LogText("Preparing update...\n"); + this->LogText("Update wird vorbereitet...\n"); m_install_state = InstallState::AwaitingPrepare; } else if (m_install_state == InstallState::AwaitingPrepare) { /* Check if preparation has a result. */ if (R_FAILED(rc = asyncResultWait(&m_prepare_result, 0)) && rc != 0xea01) { - this->LogText("Failed to check update preparation result.\nResult: 0x%08x\n", rc); + this->LogText("Ergebnis der Update-Vorbereitung konnte nicht geprüft werden.\nErgebnis: 0x%08x\n", rc); this->MarkForReboot(); return rc; } else if (R_SUCCEEDED(rc)) { if (R_FAILED(rc = asyncResultGet(&m_prepare_result))) { - this->LogText("Failed to prepare update.\nResult: 0x%08x\n", rc); + this->LogText("Update konnte nicht vorbereitet werden.\nErgebnis: 0x%08x\n", rc); this->MarkForReboot(); return rc; } @@ -1111,14 +1192,14 @@ namespace dbk { /* Check if the update has been prepared. */ bool prepared; if (R_FAILED(rc = amssuHasPreparedUpdate(&prepared))) { - this->LogText("Failed to check if update has been prepared.\nResult: 0x%08x\n", rc); + this->LogText("Prüfung, ob das Update vorbereitet wurde, fehlgeschlagen.\nErgebnis: 0x%08x\n", rc); this->MarkForReboot(); return rc; } /* Mark for application if preparation complete. */ if (prepared) { - this->LogText("Update preparation complete.\nApplying update...\n"); + this->LogText("Update-Vorbereitung abgeschlossen.\nUpdate wird angewendet...\n"); m_install_state = InstallState::NeedsApply; return rc; } @@ -1126,7 +1207,7 @@ namespace dbk { /* Check update progress. */ NsSystemUpdateProgress update_progress = {}; if (R_FAILED(rc = amssuGetPrepareUpdateProgress(&update_progress))) { - this->LogText("Failed to check update progress.\nResult: 0x%08x\n", rc); + this->LogText("Update-Fortschritt konnte nicht geprüft werden.\nErgebnis: 0x%08x\n", rc); this->MarkForReboot(); return rc; } @@ -1140,28 +1221,28 @@ namespace dbk { } else if (m_install_state == InstallState::NeedsApply) { /* Apply the prepared update. */ if (R_FAILED(rc = amssuApplyPreparedUpdate())) { - this->LogText("Failed to apply update.\nResult: 0x%08x\n", rc); + this->LogText("Update konnte nicht angewendet werden.\nErgebnis: 0x%08x\n", rc); } else { /* Log success. */ - this->LogText("Update applied successfully.\n"); + this->LogText("Update erfolgreich angewendet.\n"); if (g_reset_to_factory) { if (R_FAILED(rc = nsResetToFactorySettingsForRefurbishment())) { /* Fallback on ResetToFactorySettings. */ if (rc == MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer)) { if (R_FAILED(rc = nsResetToFactorySettings())) { - this->LogText("Failed to reset to factory settings.\nResult: 0x%08x\n", rc); + this->LogText("Zurücksetzen auf Werkseinstellungen fehlgeschlagen.\nErgebnis: 0x%08x\n", rc); this->MarkForReboot(); return rc; } } else { - this->LogText("Failed to reset to factory settings for refurbishment.\nResult: 0x%08x\n", rc); + this->LogText("Zurücksetzen für Aufbereitung fehlgeschlagen.\nErgebnis: 0x%08x\n", rc); this->MarkForReboot(); return rc; } } - this->LogText("Successfully reset to factory settings.\n", rc); + this->LogText("Erfolgreich auf Werkseinstellungen zurückgesetzt.\n", rc); } } @@ -1201,7 +1282,7 @@ namespace dbk { const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; - DrawWindow(vg, "Installing update", x, y, WindowWidth, WindowHeight); + DrawWindow(vg, "Update wird installiert", x, y, WindowWidth, WindowHeight); DrawProgressText(vg, x + HorizontalInset, y + TitleGap, m_progress_percent); DrawProgressBar(vg, x + HorizontalInset, y + TitleGap + ProgressTextHeight, WindowWidth - HorizontalInset * 2.0f, ProgressBarHeight, m_progress_percent); DrawTextBackground(vg, x + HorizontalInset, y + TitleGap + ProgressTextHeight + ProgressBarHeight + VerticalGap, WindowWidth - HorizontalInset * 2.0f, TextAreaHeight); @@ -1211,7 +1292,7 @@ namespace dbk { /* We have drawn now, allow setup to occur. */ if (m_install_state == InstallState::NeedsDraw) { - this->LogText("Beginning update setup...\n"); + this->LogText("Update-Einrichtung wird gestartet...\n"); m_install_state = InstallState::NeedsSetup; } } @@ -1236,7 +1317,7 @@ namespace dbk { /* Attempt to get the exosphere version. */ u64 version; if (R_FAILED(rc = splGetConfig(static_cast(ExosphereApiVersionConfigItem), &version))) { - ChangeMenu(std::make_shared("Atmosphere not found", "Daybreak requires Atmosphere to be installed.", rc)); + ChangeMenu(std::make_shared("Atmosphere nicht gefunden", "Daybreak benötigt eine installierte Atmosphere-Umgebung.", rc)); return false; } @@ -1247,20 +1328,22 @@ namespace dbk { /* Validate the exosphere version. */ const bool ams_supports_sysupdate_api = EncodeVersion(version_major, version_minor, version_micro) >= EncodeVersion(0, 14, 0); if (!ams_supports_sysupdate_api) { - ChangeMenu(std::make_shared("Outdated Atmosphere version", "Daybreak requires Atmosphere 0.14.0 or later.", rc)); + ChangeMenu(std::make_shared("Veraltete Atmosphere-Version", "Daybreak benötigt Atmosphere 0.14.0 oder neuer.", rc)); return false; } /* Ensure DayBreak is ran as a NRO. */ if (envIsNso()) { - ChangeMenu(std::make_shared("Unsupported Environment", "Please launch Daybreak via the Homebrew menu.", rc)); + ChangeMenu(std::make_shared("Nicht unterstützte Umgebung", "Bitte starte Daybreak über das Homebrew-Menü.", rc)); return false; } - /* Attempt to get the supported version. */ - if (R_SUCCEEDED(rc = splGetConfig(static_cast(ExosphereSupportedHosVersion), &version))) { - g_supported_version = static_cast(version); + /* Get the maximum HOS version supported by this Atmosphere build (hos::Version_Max). */ + if (R_FAILED(rc = splGetConfig(static_cast(ExosphereSupportedHosVersion), &version))) { + ChangeMenu(std::make_shared("Atmosphere nicht gefunden", "Maximal unterstützte Firmware-Version konnte nicht ermittelt werden.", rc)); + return false; } + g_supported_version = static_cast(version); /* Initialize ams:su. */ if (R_FAILED(rc = amssuInitialize())) { @@ -1280,7 +1363,7 @@ namespace dbk { strncpy(g_update_path, update_path, sizeof(g_update_path)-1); /* Change the menu. */ - ChangeMenu(std::make_shared(g_current_menu)); + ChangeMenu(CreateUpdateMenuAfterPathSelection(g_current_menu)); return true; } diff --git a/troposphere/daybreak/source/ui.hpp b/troposphere/daybreak/source/ui.hpp index 7b0a30a06..8b08965a1 100644 --- a/troposphere/daybreak/source/ui.hpp +++ b/troposphere/daybreak/source/ui.hpp @@ -120,6 +120,17 @@ namespace dbk { virtual void Update(u64 ns) override; }; + class FirmwareNotSupportedMenu : public AlertMenu { + private: + static constexpr u32 BackButtonId = 0; + static constexpr float SubTextAreaHeight = 72.0f; + public: + FirmwareNotSupportedMenu(std::shared_ptr prev_menu, u32 update_ncm_version, u32 max_supported_hos_version); + + virtual void Update(u64 ns) override; + virtual void Draw(NVGcontext *vg, u64 ns) override; + }; + class MainMenu : public Menu { private: static constexpr u32 InstallButtonId = 0; diff --git a/troposphere/daybreak/source/ui_util.cpp b/troposphere/daybreak/source/ui_util.cpp index 224ab5c52..a177b1995 100644 --- a/troposphere/daybreak/source/ui_util.cpp +++ b/troposphere/daybreak/source/ui_util.cpp @@ -148,7 +148,7 @@ namespace dbk { void DrawProgressText(NVGcontext *vg, float x, float y, float progress) { char progress_text[32] = {}; - snprintf(progress_text, sizeof(progress_text)-1, "%d%% complete", static_cast(progress * 100.0f)); + snprintf(progress_text, sizeof(progress_text)-1, "%d%% abgeschlossen", static_cast(progress * 100.0f)); nvgFontSize(vg, 24.0f); nvgFontFace(vg, SwitchStandardFont);