#include "ui/error_box.hpp" #include "ui/nvg_util.hpp" #include "app.hpp" #include "i18n.hpp" namespace sphaira::ui { namespace { auto GetModule(Result rc) -> const char* { switch (R_MODULE(rc)) { case Module_Svc: return "Svc"; case Module_Fs: return "Fs"; case Module_Os: return "Os"; case Module_Ncm: return "Ncm"; case Module_Ns: return "Ns"; case Module_Spl: return "Spl"; case Module_Applet: return "Applet"; case Module_Usb: return "Usb"; case Module_Irsensor: return "Irsensor"; case Module_Libnx: return "Libnx"; case Module_Sphaira: return "Sphaira"; } return nullptr; } auto GetCodeMessage(Result rc) -> const char* { switch (rc) { case SvcError_TimedOut: return "SvcError_TimedOut"; case SvcError_Cancelled: return "SvcError_Cancelled"; case FsError_PathNotFound: return "FsError_PathNotFound"; case FsError_PathAlreadyExists: return "FsError_PathAlreadyExists"; case FsError_TargetLocked: return "FsError_TargetLocked"; case FsError_TooLongPath: return "FsError_TooLongPath"; case FsError_InvalidCharacter: return "FsError_InvalidCharacter"; case FsError_InvalidOffset: return "FsError_InvalidOffset"; case FsError_InvalidSize: return "FsError_InvalidSize"; case Result_TransferCancelled: return "SphairaError_TransferCancelled"; case Result_StreamBadSeek: return "SphairaError_StreamBadSeek"; case Result_FsTooManyEntries: return "SphairaError_FsTooManyEntries"; case Result_FsNewPathTooLarge: return "SphairaError_FsNewPathTooLarge"; case Result_FsInvalidType: return "SphairaError_FsInvalidType"; case Result_FsEmpty: return "SphairaError_FsEmpty"; case Result_FsAlreadyRoot: return "SphairaError_FsAlreadyRoot"; case Result_FsNoCurrentPath: return "SphairaError_FsNoCurrentPath"; case Result_FsBrokenCurrentPath: return "SphairaError_FsBrokenCurrentPath"; case Result_FsIndexOutOfBounds: return "SphairaError_FsIndexOutOfBounds"; case Result_FsFsNotActive: return "SphairaError_FsFsNotActive"; case Result_FsNewPathEmpty: return "SphairaError_FsNewPathEmpty"; case Result_FsLoadingCancelled: return "SphairaError_FsLoadingCancelled"; case Result_FsBrokenRoot: return "SphairaError_FsBrokenRoot"; case Result_FsUnknownStdioError: return "SphairaError_FsUnknownStdioError"; case Result_FsReadOnly: return "SphairaError_FsReadOnly"; case Result_FsNotActive: return "SphairaError_FsNotActive"; case Result_FsFailedStdioStat: return "SphairaError_FsFailedStdioStat"; case Result_FsFailedStdioOpendir: return "SphairaError_FsFailedStdioOpendir"; case Result_NroBadMagic: return "SphairaError_NroBadMagic"; case Result_NroBadSize: return "SphairaError_NroBadSize"; case Result_AppFailedMusicDownload: return "SphairaError_AppFailedMusicDownload"; case Result_CurlFailedEasyInit: return "SphairaError_CurlFailedEasyInit"; case Result_DumpFailedNetworkUpload: return "SphairaError_DumpFailedNetworkUpload"; case Result_UnzOpen2_64: return "SphairaError_UnzOpen2_64"; case Result_UnzGetGlobalInfo64: return "SphairaError_UnzGetGlobalInfo64"; case Result_UnzLocateFile: return "SphairaError_UnzLocateFile"; case Result_UnzGoToFirstFile: return "SphairaError_UnzGoToFirstFile"; case Result_UnzGoToNextFile: return "SphairaError_UnzGoToNextFile"; case Result_UnzOpenCurrentFile: return "SphairaError_UnzOpenCurrentFile"; case Result_UnzGetCurrentFileInfo64: return "SphairaError_UnzGetCurrentFileInfo64"; case Result_UnzReadCurrentFile: return "SphairaError_UnzReadCurrentFile"; case Result_ZipOpen2_64: return "SphairaError_ZipOpen2_64"; case Result_ZipOpenNewFileInZip: return "SphairaError_ZipOpenNewFileInZip"; case Result_ZipWriteInFileInZip: return "SphairaError_ZipWriteInFileInZip"; case Result_FileBrowserFailedUpload: return "SphairaError_FileBrowserFailedUpload"; case Result_FileBrowserDirNotDaybreak: return "SphairaError_FileBrowserDirNotDaybreak"; case Result_AppstoreFailedZipDownload: return "SphairaError_AppstoreFailedZipDownload"; case Result_AppstoreFailedMd5: return "SphairaError_AppstoreFailedMd5"; case Result_AppstoreFailedParseManifest: return "SphairaError_AppstoreFailedParseManifest"; case Result_GameBadReadForDump: return "SphairaError_GameBadReadForDump"; case Result_GameEmptyMetaEntries: return "SphairaError_GameEmptyMetaEntries"; case Result_GameMultipleKeysFound: return "SphairaError_GameMultipleKeysFound"; case Result_GameNoNspEntriesBuilt: return "SphairaError_GameNoNspEntriesBuilt"; case Result_KeyMissingNcaKeyArea: return "SphairaError_KeyMissingNcaKeyArea"; case Result_KeyMissingTitleKek: return "SphairaError_KeyMissingTitleKek"; case Result_KeyMissingMasterKey: return "SphairaError_KeyMissingMasterKey"; case Result_KeyFailedDecyptETicketDeviceKey: return "SphairaError_KeyFailedDecyptETicketDeviceKey"; case Result_NcaFailedNcaHeaderHashVerify: return "SphairaError_NcaFailedNcaHeaderHashVerify"; case Result_NcaBadSigKeyGen: return "SphairaError_NcaBadSigKeyGen"; case Result_GcBadReadForDump: return "SphairaError_GcBadReadForDump"; case Result_GcEmptyGamecard: return "SphairaError_GcEmptyGamecard"; case Result_GcBadXciMagic: return "SphairaError_GcBadXciMagic"; case Result_GcBadXciRomSize: return "SphairaError_GcBadXciRomSize"; case Result_GcFailedToGetSecurityInfo: return "SphairaError_GcFailedToGetSecurityInfo"; case Result_GhdlEmptyAsset: return "SphairaError_GhdlEmptyAsset"; case Result_GhdlFailedToDownloadAsset: return "SphairaError_GhdlFailedToDownloadAsset"; case Result_GhdlFailedToDownloadAssetJson: return "SphairaError_GhdlFailedToDownloadAssetJson"; case Result_ThemezerFailedToDownloadThemeMeta: return "SphairaError_ThemezerFailedToDownloadThemeMeta"; case Result_ThemezerFailedToDownloadTheme: return "SphairaError_ThemezerFailedToDownloadTheme"; case Result_MainFailedToDownloadUpdate: return "SphairaError_MainFailedToDownloadUpdate"; case Result_UsbDsBadDeviceSpeed: return "SphairaError_UsbDsBadDeviceSpeed"; case Result_NspBadMagic: return "SphairaError_NspBadMagic"; case Result_XciBadMagic: return "SphairaError_XciBadMagic"; case Result_XciSecurePartitionNotFound: return "SphairaError_XciSecurePartitionNotFound"; case Result_EsBadTitleKeyType: return "SphairaError_EsBadTitleKeyType"; case Result_EsPersonalisedTicketDeviceIdMissmatch: return "SphairaError_EsPersonalisedTicketDeviceIdMissmatch"; case Result_EsFailedDecryptPersonalisedTicket: return "SphairaError_EsFailedDecryptPersonalisedTicket"; case Result_EsBadDecryptedPersonalisedTicketSize: return "SphairaError_EsBadDecryptedPersonalisedTicketSize"; case Result_EsInvalidTicketBadRightsId: return "SphairaError_EsInvalidTicketBadRightsId"; case Result_EsInvalidTicketFromatVersion: return "SphairaError_EsInvalidTicketFromatVersion"; case Result_EsInvalidTicketKeyType: return "SphairaError_EsInvalidTicketKeyType"; case Result_EsInvalidTicketKeyRevision: return "SphairaError_EsInvalidTicketKeyRevision"; case Result_OwoBadArgs: return "SphairaError_OwoBadArgs"; case Result_UsbCancelled: return "SphairaError_UsbCancelled"; case Result_UsbBadMagic: return "SphairaError_UsbBadMagic"; case Result_UsbBadVersion: return "SphairaError_UsbBadVersion"; case Result_UsbBadCount: return "SphairaError_UsbBadCount"; case Result_UsbBadBufferAlign: return "SphairaError_UsbBadBufferAlign"; case Result_UsbBadTransferSize: return "SphairaError_UsbBadTransferSize"; case Result_UsbEmptyTransferSize: return "SphairaError_UsbEmptyTransferSize"; case Result_UsbOverflowTransferSize: return "SphairaError_UsbOverflowTransferSize"; case Result_UsbUploadBadMagic: return "SphairaError_UsbUploadBadMagic"; case Result_UsbUploadExit: return "SphairaError_UsbUploadExit"; case Result_UsbUploadBadCount: return "SphairaError_UsbUploadBadCount"; case Result_UsbUploadBadTransferSize: return "SphairaError_UsbUploadBadTransferSize"; case Result_UsbUploadBadTotalSize: return "SphairaError_UsbUploadBadTotalSize"; case Result_UsbUploadBadCommand: return "SphairaError_UsbUploadBadCommand"; case Result_YatiContainerNotFound: return "SphairaError_YatiContainerNotFound"; case Result_YatiNcaNotFound: return "SphairaError_YatiNcaNotFound"; case Result_YatiInvalidNcaReadSize: return "SphairaError_YatiInvalidNcaReadSize"; case Result_YatiInvalidNcaSigKeyGen: return "SphairaError_YatiInvalidNcaSigKeyGen"; case Result_YatiInvalidNcaMagic: return "SphairaError_YatiInvalidNcaMagic"; case Result_YatiInvalidNcaSignature0: return "SphairaError_YatiInvalidNcaSignature0"; case Result_YatiInvalidNcaSignature1: return "SphairaError_YatiInvalidNcaSignature1"; case Result_YatiInvalidNcaSha256: return "SphairaError_YatiInvalidNcaSha256"; case Result_YatiNczSectionNotFound: return "SphairaError_YatiNczSectionNotFound"; case Result_YatiInvalidNczSectionCount: return "SphairaError_YatiInvalidNczSectionCount"; case Result_YatiNczBlockNotFound: return "SphairaError_YatiNczBlockNotFound"; case Result_YatiInvalidNczBlockVersion: return "SphairaError_YatiInvalidNczBlockVersion"; case Result_YatiInvalidNczBlockType: return "SphairaError_YatiInvalidNczBlockType"; case Result_YatiInvalidNczBlockTotal: return "SphairaError_YatiInvalidNczBlockTotal"; case Result_YatiInvalidNczBlockSizeExponent: return "SphairaError_YatiInvalidNczBlockSizeExponent"; case Result_YatiInvalidNczZstdError: return "SphairaError_YatiInvalidNczZstdError"; case Result_YatiTicketNotFound: return "SphairaError_YatiTicketNotFound"; case Result_YatiInvalidTicketBadRightsId: return "SphairaError_YatiInvalidTicketBadRightsId"; case Result_YatiCertNotFound: return "SphairaError_YatiCertNotFound"; case Result_YatiNcmDbCorruptHeader: return "SphairaError_YatiNcmDbCorruptHeader"; case Result_YatiNcmDbCorruptInfos: return "SphairaError_YatiNcmDbCorruptInfos"; } return ""; } } // namespace ErrorBox::ErrorBox(const std::string& message) : m_message{message} { log_write("[ERROR] %s\n", m_message.c_str()); m_pos.w = 770.f; m_pos.h = 430.f; m_pos.x = 255; m_pos.y = 145; SetAction(Button::A, Action{[this](){ SetPop(); }}); App::PlaySoundEffect(SoundEffect::SoundEffect_Error); } ErrorBox::ErrorBox(Result code, const std::string& message) : ErrorBox{message} { m_code = code; m_code_message = GetCodeMessage(code); m_code_module = std::to_string(R_MODULE(code)); if (auto str = GetModule(code)) { m_code_module += " (" + std::string(str) + ")"; } log_write("[ERROR] Code: 0x%X Module: %s Description: %u\n", R_VALUE(code), m_code_module.c_str(), R_DESCRIPTION(code)); } auto ErrorBox::Update(Controller* controller, TouchInfo* touch) -> void { Widget::Update(controller, touch); } auto ErrorBox::Draw(NVGcontext* vg, Theme* theme) -> void { gfx::dimBackground(vg); gfx::drawRect(vg, m_pos, theme->GetColour(ThemeEntryID_POPUP)); const Vec4 box = { 455, 470, 365, 65 }; const auto center_x = m_pos.x + m_pos.w/2; gfx::drawTextArgs(vg, center_x, 180, 63, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_ERROR), "\uE140"); if (m_code.has_value()) { const auto code = m_code.value(); if (m_code_message.empty()) { gfx::drawTextArgs(vg, center_x, 270, 25, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Code: 0x%X Module: %s", R_VALUE(code), m_code_module.c_str()); } else { gfx::drawTextArgs(vg, center_x, 270, 25, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s", m_code_message.c_str()); } } else { gfx::drawTextArgs(vg, center_x, 270, 25, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "An error occurred"_i18n.c_str()); } gfx::drawTextArgs(vg, center_x, 325, 23, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s", m_message.c_str()); gfx::drawTextArgs(vg, center_x, 380, 20, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_INFO), "If this message appears repeatedly, please open an issue."_i18n.c_str()); gfx::drawTextArgs(vg, center_x, 415, 20, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_INFO), "https://github.com/ITotalJustice/sphaira/issues"); gfx::drawRectOutline(vg, theme, 4.f, box); gfx::drawTextArgs(vg, center_x, box.y + box.h/2, 23, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_SELECTED), "OK"_i18n.c_str()); } } // namespace sphaira::ui