diff --git a/Makefile b/Makefile index ecfeb32..bce14e4 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ GRAPHICS := assets/gfx ROMFS := romfs GFXBUILD := $(ROMFS)/gfx APP_AUTHOR := Universal-Team -APP_DESCRIPTION := A universally good updater! +APP_DESCRIPTION := A multiapp, JSON script-based updater for Nintendo 3DS ICON := app/icon.png BNR_IMAGE := app/banner.png BNR_AUDIO := app/BannerAudio.wav diff --git a/README.md b/README.md index 1dd3d21..de8df2d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,35 @@ -# Universal-Updater -A universally good updater! :) +

+
+ A multiapp, JSON script-based updater for Nintendo 3DS +

+ +

+ + + + + + + + + +

+ +## Features + +Universal-Updater is packed with features! Some include the JSON script updater, an App store, an FTP server, and more! + +- JSON-based Script updater +- JSON Script Downloader +- An App Store, the UniStore +- A Settings page, for configuring Universal-Updater Settings +- An FTP Server + + +## Compilation + +To build Universal-Updater from source, you need devkitPro installed, along with devkitARM, libctru, 3ds-curl, and 3ds-libarchive. To get these you can run `pacman -S 3ds-dev --noconfirm`, then `pacman -S 3ds-curl --noconfirm`, and lastly `pacman -S 3ds-libarchive --noconfirm`. Now that you have everything installed, you just need to run clone the repository and run `make` + +## Screenshots + +![](https://universal-team.github.io/images/universal-updater/script-browse-3.png)![](https://universal-team.github.io/images/universal-updater/script-browse-7.png)![](https://universal-team.github.io/images/universal-updater/scriptlist-selection.png)![](https://universal-team.github.io/images/universal-updater/mainMenu.png) diff --git a/app/banner.bin b/app/banner.bin deleted file mode 100644 index 3078df3..0000000 Binary files a/app/banner.bin and /dev/null differ diff --git a/app/banner.png b/app/banner.png index 8f4c45b..a96e75f 100644 Binary files a/app/banner.png and b/app/banner.png differ diff --git a/app/icon.bin b/app/icon.bin deleted file mode 100644 index 60e1367..0000000 Binary files a/app/icon.bin and /dev/null differ diff --git a/assets/gfx/sprites.t3s b/assets/gfx/sprites.t3s index 8e0fee4..70c818c 100644 --- a/assets/gfx/sprites.t3s +++ b/assets/gfx/sprites.t3s @@ -8,6 +8,9 @@ sprites/top_screen_bot.png sprites/top_screen_top.png sprites/search.png sprites/side_arrow.png +sprites/uniStore.png +sprites/uniStore_HD.png +sprites/update.png sprites/view.png sprites/credits/discord.png diff --git a/assets/gfx/sprites/uniStore.png b/assets/gfx/sprites/uniStore.png new file mode 100644 index 0000000..7a971ac Binary files /dev/null and b/assets/gfx/sprites/uniStore.png differ diff --git a/assets/gfx/sprites/uniStore_HD.png b/assets/gfx/sprites/uniStore_HD.png new file mode 100644 index 0000000..ad58417 Binary files /dev/null and b/assets/gfx/sprites/uniStore_HD.png differ diff --git a/assets/gfx/sprites/update.png b/assets/gfx/sprites/update.png new file mode 100644 index 0000000..05fc862 Binary files /dev/null and b/assets/gfx/sprites/update.png differ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 119af5a..0005189 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,7 +1,7 @@ trigger: branches: include: ['*'] - exclude: [translation, script-creator-experimental] + exclude: [translation, App-Store, Camera] tags: include: ['*'] diff --git a/include/screens/mainMenu.hpp b/include/screens/mainMenu.hpp index f6bc41e..4a84486 100644 --- a/include/screens/mainMenu.hpp +++ b/include/screens/mainMenu.hpp @@ -41,8 +41,9 @@ public: void Logic(u32 hDown, u32 hHeld, touchPosition touch) override; private: bool returnScriptState(); + bool returnStoreState(); int Selection = 0; - std::vector dirContents; // To return Script state. + std::vector dirContents; // To return Script/Store state. std::vector mainButtons = { {10, 40, 140, 35, -1}, // Scriptlist. {170, 40, 140, 35, -1}, // ScriptBrowse. diff --git a/include/screens/tinyDB.hpp b/include/screens/unistore.hpp similarity index 70% rename from include/screens/tinyDB.hpp rename to include/screens/unistore.hpp index 627a989..7c1bff6 100644 --- a/include/screens/tinyDB.hpp +++ b/include/screens/unistore.hpp @@ -24,34 +24,60 @@ * reasonable ways as different from the original version. */ -#ifndef TINYDB_HPP -#define TINYDB_HPP +#ifndef UNISTORE_HPP +#define UNISTORE_HPP #include "screens/screen.hpp" #include "screens/screenCommon.hpp" +#include "utils/fileBrowse.h" #include "utils/structs.hpp" -class TinyDB : public screen +class UniStore : public screen { public: void Draw(void) const override; void Logic(u32 hDown, u32 hHeld, touchPosition touch) override; - TinyDB(); + UniStore(); private: + void DrawStoreList(void) const; + void DrawStore(void) const; + void DrawSearch(void) const; + + void StoreSelectionLogic(u32 hDown, u32 hHeld, touchPosition touch); + void StoreLogic(u32 hDown, u32 hHeld, touchPosition touch); + void SearchLogic(u32 hDown, u32 hHeld, touchPosition touch); void execute(); + void descript(); + int mode = 0; + std::string selectedOptionAppStore; + mutable int selection = 0; + mutable int selection2 = 0; int screenPos = 0; + int screenPos2 = 0; mutable int screenPosList = 0; + mutable int screenPosList2 = 0; + + int searchSelection = 0; + int keyRepeatDelay = 0; int fastMode = false; + std::vector dirContents; + std::vector arrowPos = { {295, 0, 25, 25, -1}, // Arrow Up. {295, 215, 25, 25, -1}, // Arrow Down. {0, 215, 25, 25, -1}, // Back Arrow. {5, 0, 25, 25, -1}, // ViewMode Change. {45, 0, 25, 25, -1}, // Search. + {85, 0, 25, 25, -1}, // Update. + }; + + std::vector URLBtn = { + {10, 100, 140, 35, -1}, // FULL URL. + {170, 100, 140, 35, -1}, // Github. }; }; diff --git a/include/utils/common.hpp b/include/utils/common.hpp index f4204ef..bdd3cda 100644 --- a/include/utils/common.hpp +++ b/include/utils/common.hpp @@ -61,4 +61,7 @@ extern char * arg0; #define WORKING_DIR "/" #define SCRIPTS_PATH "sdmc:/3ds/Universal-Updater/scripts/" // The Scripts will be here. #define MUSIC_PATH "sdmc:/3ds/Universal-Updater/Music.wav" // Default Music File / Path. -#define SCRIPT_VERSION 3 \ No newline at end of file +#define SCRIPT_VERSION 3 +#define STORE_PATH "sdmc:/3ds/Universal-Updater/stores/" // Default Store path. +#define ENTRIES_PER_SCREEN 3 +#define ENTRIES_PER_LIST 7 \ No newline at end of file diff --git a/include/utils/config.hpp b/include/utils/config.hpp index 846d329..68b62ac 100644 --- a/include/utils/config.hpp +++ b/include/utils/config.hpp @@ -31,7 +31,7 @@ namespace Config { extern int lang, Color1, Color2, Color3, TxtColor, SelectedColor, UnselectedColor, viewMode, ColorKeys, progressbarColor; - extern std::string ScriptPath, MusicPath; + extern std::string ScriptPath, MusicPath, StorePath; extern bool Logging, UseBars; void load(); diff --git a/include/utils/scriptHelper.hpp b/include/utils/scriptHelper.hpp index 0ced401..22d9fd3 100644 --- a/include/utils/scriptHelper.hpp +++ b/include/utils/scriptHelper.hpp @@ -44,7 +44,7 @@ namespace ScriptHelper { Result createFile(const char * path); void displayTimeMsg(std::string message, int seconds); - bool checkIfValid(std::string scriptFile); + bool checkIfValid(std::string scriptFile, int mode = 0); } #endif \ No newline at end of file diff --git a/romfs/lang/en/app.json b/romfs/lang/en/app.json index 22fcfac..9e86fd8 100644 --- a/romfs/lang/en/app.json +++ b/romfs/lang/en/app.json @@ -86,8 +86,26 @@ "FILEBROWSE_MSG": "Press X to select, Select to refresh.", "SELECT_SCRIPT_PATH": "Select the Script Path.", - "CHANGE_BARS": "Change Bars", + "USE_BARS": "Use Bars:", "CHANGE_SCRIPTPATH": "Change Scriptpath", "CHANGE_MUSICFILE": "Change Musicfile", - "SELECT_MUSIC_FILE": "Select the Musicfile." + "SELECT_MUSIC_FILE": "Select the Musicfile.", + + "PULLING_APPSTORE": "Pulling App Store data...", + "VERSION": "Version: ", + "UPDATING": "Updating...", + "WOULD_YOU_LIKE_UPDATE": "Would you like to update this store?", + "GET_STORES_FIRST": "Get some Stores first!", + "PREPARE_STORE": "Prepare store... please wait.", + "YES": "Yes", + "NO": "No", + "CHANGE_STOREPATH": "Change Storepath", + "SELECT_STORE_PATH": "Select the Store Path.", + "UNKNOWN": "Unknown", + "ENTER_OWNER_AND_REPO": "Enter Owner and Repo.", + "ENTER_FILENAME": "Enter filename.", + "UNISTORE_SEARCH": "UniStore search", + "FULL_URL": "Full URL", + "GITHUB": "Github", + "ENTER_FULL_URL": "Enter the full URL." } diff --git a/source/gui.cpp b/source/gui.cpp index 8d3d8bd..07c51ce 100644 --- a/source/gui.cpp +++ b/source/gui.cpp @@ -29,6 +29,7 @@ #include "screens/screenCommon.hpp" #include "utils/config.hpp" +#include "utils/structs.hpp" C3D_RenderTarget* top; C3D_RenderTarget* bottom; @@ -247,6 +248,14 @@ void Gui::DrawBottom(void) { } } +std::vector promptBtn = { + {10, 100, 140, 35, -1}, // Yes. + {170, 100, 140, 35, -1}, // No. +}; + +extern touchPosition touch; +extern bool touching(touchPosition touch, Structs::ButtonPos button); + // Display a Message, which needs to be confirmed with A/B. bool Gui::promptMsg(std::string promptMsg) { @@ -263,14 +272,27 @@ bool Gui::promptMsg(std::string promptMsg) Gui::DrawString((400-Gui::GetStringWidth(0.72f, Lang::get("CONFIRM_OR_CANCEL")))/2, 217, 0.72f, TextColor, Lang::get("CONFIRM_OR_CANCEL"), 400); } Gui::DrawBottom(); + if (isScriptSelected == false) { + Gui::Draw_Rect(10, 100, 140, 35, Config::Color1); + Gui::Draw_Rect(170, 100, 140, 35, Config::Color1); + Gui::DrawString((320-Gui::GetStringWidth(0.6f, Lang::get("YES")))/2-150+70, 110, 0.6f, Config::TxtColor, Lang::get("YES"), 140); + Gui::DrawString((320-Gui::GetStringWidth(0.6f, Lang::get("NO")))/2+150-70, 110, 0.6f, Config::TxtColor, Lang::get("NO"), 140); + } else if (isScriptSelected == true) { + Gui::Draw_Rect(10, 100, 140, 35, barColor); + Gui::Draw_Rect(170, 100, 140, 35, barColor); + Gui::DrawString((320-Gui::GetStringWidth(0.6f, Lang::get("YES")))/2-150+70, 110, 0.6f, TextColor, Lang::get("YES"), 140); + Gui::DrawString((320-Gui::GetStringWidth(0.6f, Lang::get("NO")))/2+150-70, 110, 0.6f, TextColor, Lang::get("NO"), 140); + } + C3D_FrameEnd(0); while(1) { gspWaitForVBlank(); hidScanInput(); - if(hidKeysDown() & KEY_A) { + hidTouchRead(&touch); + if ((hidKeysDown() & KEY_A) || (hidKeysDown() & KEY_TOUCH && touching(touch, promptBtn[0]))) { return true; - } else if(hidKeysDown() & KEY_B) { + } else if ((hidKeysDown() & KEY_B) || (hidKeysDown() & KEY_TOUCH && touching(touch, promptBtn[1]))) { return false; } } diff --git a/source/keyboard.cpp b/source/keyboard.cpp index a4bbd6b..408a3ee 100644 --- a/source/keyboard.cpp +++ b/source/keyboard.cpp @@ -205,7 +205,7 @@ std::string Input::getString(uint maxLength, std::string Text) { Gui::DrawBottom(); drawKeyboard(); C2D_DrawRectSolid(0, 81, 0.5f, 320, 20, Config::ColorKeys & C2D_Color32(200, 200, 200, 200)); - Gui::DrawString(5, 82, 0.6, Config::TxtColor, (string+(cursorBlink-- > 0 ? "_" : "")).c_str()); + Gui::DrawString(2, 82, 0.6, Config::TxtColor, (string+(cursorBlink-- > 0 ? "_" : "")).c_str()); if(cursorBlink < -20) cursorBlink = 20; scanKeys(); hDown = keysDown(); diff --git a/source/main.cpp b/source/main.cpp index 94eb92a..e62f33c 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -88,6 +88,7 @@ int main() mkdir("sdmc:/3ds", 0777); mkdir("sdmc:/3ds/Universal-Updater", 0777); mkdir("sdmc:/3ds/Universal-Updater/scripts", 0777); + mkdir("sdmc:/3ds/Universal-Updater/stores", 0777); // We need to make sure, the file exist. if(access("sdmc:/3ds/Universal-Updater/Settings.json", F_OK) == -1 ) { diff --git a/source/screens/ftpScreen.cpp b/source/screens/ftpScreen.cpp index 0f8374a..755cf24 100644 --- a/source/screens/ftpScreen.cpp +++ b/source/screens/ftpScreen.cpp @@ -88,9 +88,7 @@ void FTPScreen::Draw(void) const hidTouchRead(&touch); u32 hDown = hidKeysDown(); - if (hDown & KEY_B) - break; - if (hDown & KEY_TOUCH && touching(touch, arrowPos[0])) + if ((hDown & KEY_B) || (hDown & KEY_TOUCH && touching(touch, arrowPos[0]))) break; } memset(ftp_accepted_connection, 0, 20); // Empty accepted connection address. diff --git a/source/screens/mainMenu.cpp b/source/screens/mainMenu.cpp index 38b1e41..be8a20e 100644 --- a/source/screens/mainMenu.cpp +++ b/source/screens/mainMenu.cpp @@ -32,7 +32,7 @@ #include "screens/scriptCreator.hpp" #include "screens/scriptlist.hpp" #include "screens/settings.hpp" -#include "screens/tinyDB.hpp" +#include "screens/unistore.hpp" #include "utils/config.hpp" @@ -71,9 +71,11 @@ void MainMenu::Draw(void) const { } } + // Draw UniStore Icon. ;P + Gui::sprite(sprites_uniStore_idx, 15, 95); Gui::DrawString((320-Gui::GetStringWidth(0.6f, Lang::get("SCRIPTLIST")))/2-150+70, mainButtons[0].y+10, 0.6f, Config::TxtColor, Lang::get("SCRIPTLIST"), 140); Gui::DrawString((320-Gui::GetStringWidth(0.6f, Lang::get("GET_SCRIPTS")))/2+150-70, mainButtons[1].y+10, 0.6f, Config::TxtColor, Lang::get("GET_SCRIPTS"), 140); - Gui::DrawString((320-Gui::GetStringWidth(0.6f, "TinyDB"))/2-150+70, mainButtons[2].y+10, 0.6f, Config::TxtColor, "TinyDB", 140); + Gui::DrawString(80, mainButtons[2].y+10, 0.6f, Config::TxtColor, "UniStore", 140); Gui::DrawString((320-Gui::GetStringWidth(0.6f, Lang::get("SCRIPTCREATOR")))/2+150-70, mainButtons[3].y+10, 0.6f, Config::TxtColor, Lang::get("SCRIPTCREATOR"), 140); Gui::DrawString((320-Gui::GetStringWidth(0.6f, Lang::get("SETTINGS")))/2-150+70, mainButtons[4].y+10, 0.6f, Config::TxtColor, Lang::get("SETTINGS"), 140); Gui::DrawString((320-Gui::GetStringWidth(0.6f, "FTP"))/2+150-70, mainButtons[5].y+10, 0.6f, Config::TxtColor, "FTP", 140); @@ -95,6 +97,21 @@ bool MainMenu::returnScriptState() { return true; } +bool MainMenu::returnStoreState() { + dirContents.clear(); + chdir(Config::StorePath.c_str()); + std::vector dirContentsTemp; + getDirectoryContents(dirContentsTemp, {"unistore"}); + for(uint i=0;i()); + if (returnStoreState() == true) { + Screen::set(std::make_unique()); } else { - notConnectedMsg(); + Gui::DisplayWarnMsg(Lang::get("GET_STORES_FIRST")); } break; case 3: @@ -161,6 +178,7 @@ void MainMenu::Logic(u32 hDown, u32 hHeld, touchPosition touch) { } } + if (hDown & KEY_TOUCH) { if (touching(touch, mainButtons[0])) { if (returnScriptState() == true) { @@ -175,10 +193,10 @@ void MainMenu::Logic(u32 hDown, u32 hHeld, touchPosition touch) { notConnectedMsg(); } } else if (touching(touch, mainButtons[2])) { - if (checkWifiStatus() == true) { - Screen::set(std::make_unique()); + if (returnStoreState() == true) { + Screen::set(std::make_unique()); } else { - notConnectedMsg(); + Gui::DisplayWarnMsg(Lang::get("GET_STORES_FIRST")); } } else if (touching(touch, mainButtons[3])) { if (isTesting == true) { diff --git a/source/screens/scriptBrowse.cpp b/source/screens/scriptBrowse.cpp index 83d7ba7..27ec225 100644 --- a/source/screens/scriptBrowse.cpp +++ b/source/screens/scriptBrowse.cpp @@ -34,8 +34,6 @@ #include extern bool touching(touchPosition touch, Structs::ButtonPos button); -#define ENTRIES_PER_SCREEN 3 -#define ENTRIES_PER_LIST 7 nlohmann::json infoJson; @@ -178,35 +176,13 @@ void ScriptBrowse::Draw(void) const { void ScriptBrowse::Logic(u32 hDown, u32 hHeld, touchPosition touch) { if (keyRepeatDelay) keyRepeatDelay--; - if (hDown & KEY_B) { + if ((hDown & KEY_B) || (hDown & KEY_TOUCH && touching(touch, arrowPos[2]))) { infoJson.clear(); Screen::back(); return; } - if (hDown & KEY_TOUCH && touching(touch, arrowPos[0])) { - if (selection > 0) { - selection--; - } else { - selection = (int)infoJson.size()-1; - } - } - - if (hDown & KEY_TOUCH && touching(touch, arrowPos[1])) { - if (selection < (int)infoJson.size()-1) { - selection++; - } else { - selection = 0; - } - } - - if (hDown & KEY_TOUCH && touching(touch, arrowPos[2])) { - infoJson.clear(); - Screen::back(); - return; - } - - if (hHeld & KEY_DOWN && !keyRepeatDelay) { + if ((hHeld & KEY_DOWN && !keyRepeatDelay) || (hDown & KEY_TOUCH && touching(touch, arrowPos[1]))) { if (selection < (int)infoJson.size()-1) { selection++; } else { @@ -219,7 +195,7 @@ void ScriptBrowse::Logic(u32 hDown, u32 hHeld, touchPosition touch) { } } - if (hHeld & KEY_UP && !keyRepeatDelay) { + if ((hHeld & KEY_UP && !keyRepeatDelay) || (hDown & KEY_TOUCH && touching(touch, arrowPos[0]))) { if (selection > 0) { selection--; } else { @@ -295,7 +271,7 @@ void ScriptBrowse::Logic(u32 hDown, u32 hHeld, touchPosition touch) { fastMode = false; } - if (hDown & KEY_X || hDown & KEY_TOUCH && touching(touch, arrowPos[4])) { + if ((hDown & KEY_X) || (hDown & KEY_TOUCH && touching(touch, arrowPos[4]))) { if (Config::viewMode == 0) { Config::viewMode = 1; } else { @@ -317,26 +293,7 @@ void ScriptBrowse::Logic(u32 hDown, u32 hHeld, touchPosition touch) { } } - if (hDown & KEY_Y) { - if (infoJson.size() != 0) { - for (int i = 0; i < (int)infoJson.size(); i++) { - int current = i+1; - int total = infoJson.size(); - std::string fileName = Lang::get("DOWNLOADING") + std::string(infoJson[i]["title"]); - std::string titleFix = infoJson[i]["title"]; - for (int l = 0; l < (int)titleFix.size(); l++) { - if (titleFix[l] == '/') { - titleFix[l] = '-'; - } - } - DisplayMsg(fileName + " " + std::to_string(current) + " / " + std::to_string(total)); - downloadToFile(infoJson[i]["url"], Config::ScriptPath + titleFix + ".json"); - infoJson[i]["curRevision"] = infoJson[i]["revision"]; - } - } - } - - if (hDown & KEY_TOUCH && touching(touch, arrowPos[3])) { + if ((hDown & KEY_Y) || (hDown & KEY_TOUCH && touching(touch, arrowPos[3]))) { if (infoJson.size() != 0) { for (int i = 0; i < (int)infoJson.size(); i++) { int current = i+1; diff --git a/source/screens/scriptlist.cpp b/source/screens/scriptlist.cpp index 9957aba..84f54bd 100644 --- a/source/screens/scriptlist.cpp +++ b/source/screens/scriptlist.cpp @@ -37,8 +37,6 @@ #include extern bool touching(touchPosition touch, Structs::ButtonPos button); -#define ENTRIES_PER_SCREEN 3 -#define ENTRIES_PER_LIST 7 bool isScriptSelected = false; @@ -384,32 +382,36 @@ void ScriptList::DrawSingleObject(void) const { void ScriptList::ListSelection(u32 hDown, u32 hHeld, touchPosition touch) { if (keyRepeatDelay) keyRepeatDelay--; - if (hDown & KEY_B) { + if ((hDown & KEY_B) || (hDown & KEY_TOUCH && touching(touch, arrowPos[2]))) { fileInfo.clear(); Screen::back(); return; } - if (hDown & KEY_TOUCH && touching(touch, arrowPos[0])) { - if (selection > 0) { - selection--; - } else { - selection = (int)fileInfo.size()-1; - } - } - - if (hDown & KEY_TOUCH && touching(touch, arrowPos[1])) { + if ((hHeld & KEY_DOWN && !keyRepeatDelay) || (hDown & KEY_TOUCH && touching(touch, arrowPos[1]))) { if (selection < (int)fileInfo.size()-1) { selection++; } else { selection = 0; } + if (fastMode == true) { + keyRepeatDelay = 3; + } else if (fastMode == false){ + keyRepeatDelay = 6; + } } - if (hDown & KEY_TOUCH && touching(touch, arrowPos[2])) { - fileInfo.clear(); - Screen::back(); - return; + if ((hHeld & KEY_UP && !keyRepeatDelay) || (hDown & KEY_TOUCH && touching(touch, arrowPos[0]))) { + if (selection > 0) { + selection--; + } else { + selection = (int)fileInfo.size()-1; + } + if (fastMode == true) { + keyRepeatDelay = 3; + } else if (fastMode == false){ + keyRepeatDelay = 6; + } } if (hDown & KEY_TOUCH) { @@ -457,31 +459,6 @@ void ScriptList::ListSelection(u32 hDown, u32 hHeld, touchPosition touch) { } } } - - if (hHeld & KEY_DOWN && !keyRepeatDelay) { - if (selection < (int)fileInfo.size()-1) { - selection++; - } else { - selection = 0; - } - if (fastMode == true) { - keyRepeatDelay = 3; - } else if (fastMode == false){ - keyRepeatDelay = 6; - } - } - if (hHeld & KEY_UP && !keyRepeatDelay) { - if (selection > 0) { - selection--; - } else { - selection = (int)fileInfo.size()-1; - } - if (fastMode == true) { - keyRepeatDelay = 3; - } else if (fastMode == false){ - keyRepeatDelay = 6; - } - } if (hDown & KEY_A) { if (dirContents[selection].isDirectory) { @@ -527,27 +504,38 @@ void ScriptList::ListSelection(u32 hDown, u32 hHeld, touchPosition touch) { void ScriptList::SelectFunction(u32 hDown, u32 hHeld, touchPosition touch) { if (keyRepeatDelay) keyRepeatDelay--; - if (hDown & KEY_TOUCH && touching(touch, arrowPos[0])) { - if (selection2 > 0) { - selection2--; - } else { - selection2 = (int)fileInfo2.size()-1; - } + + if ((hDown & KEY_B) || (hDown & KEY_TOUCH && touching(touch, arrowPos[2]))) { + selection2 = 0; + fileInfo2.clear(); + isScriptSelected = false; + mode = 0; } - if (hDown & KEY_TOUCH && touching(touch, arrowPos[1])) { + if ((hHeld & KEY_DOWN && !keyRepeatDelay) || (hDown & KEY_TOUCH && touching(touch, arrowPos[1]))) { if (selection2 < (int)fileInfo2.size()-1) { selection2++; } else { selection2 = 0; } + if (fastMode == true) { + keyRepeatDelay = 3; + } else if (fastMode == false){ + keyRepeatDelay = 6; + } } - if (hDown & KEY_TOUCH && touching(touch, arrowPos[2])) { - selection2 = 0; - fileInfo2.clear(); - isScriptSelected = false; - mode = 0; + if ((hHeld & KEY_UP && !keyRepeatDelay) || (hDown & KEY_TOUCH && touching(touch, arrowPos[0]))) { + if (selection2 > 0) { + selection2--; + } else { + selection2 = (int)fileInfo2.size()-1; + } + if (fastMode == true) { + keyRepeatDelay = 3; + } else if (fastMode == false){ + keyRepeatDelay = 6; + } } if (hDown & KEY_TOUCH) { @@ -572,32 +560,6 @@ void ScriptList::SelectFunction(u32 hDown, u32 hHeld, touchPosition touch) { } } - if (hHeld & KEY_DOWN && !keyRepeatDelay) { - if (selection2 < (int)fileInfo2.size()-1) { - selection2++; - } else { - selection2 = 0; - } - if (fastMode == true) { - keyRepeatDelay = 3; - } else if (fastMode == false){ - keyRepeatDelay = 6; - } - } - - if (hHeld & KEY_UP && !keyRepeatDelay) { - if (selection2 > 0) { - selection2--; - } else { - selection2 = (int)fileInfo2.size()-1; - } - if (fastMode == true) { - keyRepeatDelay = 3; - } else if (fastMode == false){ - keyRepeatDelay = 6; - } - } - if (hDown & KEY_A) { if (fileInfo2.size() != 0) { choice = fileInfo2[selection2]; @@ -623,13 +585,6 @@ void ScriptList::SelectFunction(u32 hDown, u32 hHeld, touchPosition touch) { Config::save(); } - if (hDown & KEY_B) { - selection2 = 0; - fileInfo2.clear(); - isScriptSelected = false; - mode = 0; - } - if (Config::viewMode == 0) { if(selection2 < screenPos2) { screenPos2 = selection2; @@ -653,7 +608,7 @@ void ScriptList::Logic(u32 hDown, u32 hHeld, touchPosition touch) { SelectFunction(hDown, hHeld, touch); } - if (hDown & KEY_X || hDown & KEY_TOUCH && touching(touch, arrowPos[3])) { + if ((hDown & KEY_X) || (hDown & KEY_TOUCH && touching(touch, arrowPos[3]))) { if (Config::viewMode == 0) { Config::viewMode = 1; } else { diff --git a/source/screens/settings.cpp b/source/screens/settings.cpp index 8cc8f6a..3fd12fc 100644 --- a/source/screens/settings.cpp +++ b/source/screens/settings.cpp @@ -137,23 +137,23 @@ void Settings::DrawColorChanging(void) const { Gui::DrawArrow(0, 0, 0, 1); Gui::DrawArrow(318, 22, 180.0, 1); - for (int i = 0; i < 7; i++) { + for (int i = 0; i < 8; i++) { if (colorMode == i) { Gui::Draw_Rect(54 + i * 25, 2, 16, 16, C2D_Color32(140, 140, 140, 255)); } } - Gui::DrawString(58 + 0 * 25, 2, 0.5f, WHITE, "1", 400); - Gui::DrawString(58 + 1 * 25, 2, 0.5f, WHITE, "2", 400); - Gui::DrawString(58 + 2 * 25, 2, 0.5f, WHITE, "3", 400); - Gui::DrawString(58 + 3 * 25, 2, 0.5f, WHITE, "4", 400); - Gui::DrawString(58 + 4 * 25, 2, 0.5f, WHITE, "5", 400); - Gui::DrawString(58 + 5 * 25, 2, 0.5f, WHITE, "6", 400); - Gui::DrawString(58 + 6 * 25, 2, 0.5f, WHITE, "7", 400); + for (int i = 0; i < 8; i++) { + Gui::DrawString(58 + i * 25, 2, 0.5f, WHITE, std::to_string(i+1), 400); + } - Gui::Draw_Rect(buttons[0].x, buttons[0].y, 95, 41, C2D_Color32(255, 0, 0, 255)); - Gui::Draw_Rect(buttons[1].x, buttons[1].y, 95, 41, C2D_Color32(0, 255, 0, 255)); - Gui::Draw_Rect(buttons[2].x, buttons[2].y, 95, 41, C2D_Color32(0, 0, 255, 255)); + if (colorMode != 7) { + Gui::Draw_Rect(buttons[0].x, buttons[0].y, 95, 41, C2D_Color32(255, 0, 0, 255)); + Gui::Draw_Rect(buttons[1].x, buttons[1].y, 95, 41, C2D_Color32(0, 255, 0, 255)); + Gui::Draw_Rect(buttons[2].x, buttons[2].y, 95, 41, C2D_Color32(0, 0, 255, 255)); + } else { + Gui::Draw_Rect(buttons[1].x, buttons[1].y, 95, 41, Config::Color1); + } if (colorMode == 0) { Gui::DrawStringCentered(0, 60, 0.7f, Config::TxtColor, Lang::get("BAR_COLOR"), 320); @@ -190,6 +190,10 @@ void Settings::DrawColorChanging(void) const { Gui::DrawString(40, 98, 0.7f, WHITE, ColorHelper::getColorName(Config::progressbarColor, 2).c_str(), 400); Gui::DrawString(140, 98, 0.7f, WHITE, ColorHelper::getColorName(Config::progressbarColor, 1).c_str(), 400); Gui::DrawString(245, 98, 0.7f, WHITE, ColorHelper::getColorName(Config::progressbarColor, 0).c_str(), 400); + } else if (colorMode == 7) { + Gui::DrawStringCentered(0, 60, 0.7f, Config::TxtColor, Lang::get("USE_BARS"), 320); + if (Config::UseBars == true) Gui::DrawString(140, 98, 0.7f, WHITE, Lang::get("YES"), 400); + else if (Config::UseBars == false) Gui::DrawString(140, 98, 0.7f, WHITE, Lang::get("NO"), 400); } } @@ -249,26 +253,25 @@ void Settings::DrawMiscSettings(void) const { } } - Gui::DrawStringCentered(0, mainButtons[0].y+10, 0.6f, Config::TxtColor, Lang::get("CHANGE_BARS"), 140); + Gui::DrawStringCentered(0, mainButtons[0].y+10, 0.6f, Config::TxtColor, Lang::get("CHANGE_STOREPATH"), 140); Gui::DrawStringCentered(0, mainButtons[1].y+10, 0.6f, Config::TxtColor, Lang::get("CHANGE_SCRIPTPATH"), 140); Gui::DrawStringCentered(0, mainButtons[2].y+10, 0.6f, Config::TxtColor, Lang::get("CHANGE_MUSICFILE"), 140); } void Settings::MiscSettingsLogic(u32 hDown, u32 hHeld, touchPosition touch) { if (hDown & KEY_UP) { - if(Selection > 0) Selection--; + if (Selection > 0) Selection--; } if (hDown & KEY_DOWN) { - if(Selection < 2) Selection++; + if (Selection < 2) Selection++; } if (hDown & KEY_A) { if (Selection == 0) { - if (Config::UseBars == true) { - Config::UseBars = false; - } else if (Config::UseBars == false) { - Config::UseBars = true; + std::string tempStore = selectFilePath(Lang::get("SELECT_STORE_PATH"), {}); + if (tempStore != "") { + Config::StorePath = tempStore; } } else if (Selection == 1) { std::string tempScript = selectFilePath(Lang::get("SELECT_SCRIPT_PATH"), {}); @@ -285,10 +288,9 @@ void Settings::MiscSettingsLogic(u32 hDown, u32 hHeld, touchPosition touch) { if (hDown & KEY_TOUCH) { if (touching(touch, mainButtons[0])) { - if (Config::UseBars == true) { - Config::UseBars = false; - } else if (Config::UseBars == false) { - Config::UseBars = true; + std::string tempStore = selectFilePath(Lang::get("SELECT_STORE_PATH"), {}); + if (tempStore != "") { + Config::StorePath = tempStore; } } else if (touching(touch, mainButtons[1])) { std::string tempScript = selectFilePath(Lang::get("SELECT_SCRIPT_PATH"), {}); @@ -303,11 +305,7 @@ void Settings::MiscSettingsLogic(u32 hDown, u32 hHeld, touchPosition touch) { } } - if (hDown & KEY_B || hDown & KEY_L) { - mode = 0; - } - - if (hDown & KEY_TOUCH && touching(touch, arrowPos[2])) { + if ((hDown & KEY_B || hDown & KEY_L) || (hDown & KEY_TOUCH && touching(touch, arrowPos[2]))) { mode = 0; } } @@ -323,17 +321,7 @@ void Settings::SubMenuLogic(u32 hDown, u32 hHeld, touchPosition touch) { } if (hDown & KEY_A) { - switch(Selection) { - case 0: - mode = 1; - break; - case 1: - mode = 2; - break; - case 2: - mode = 3; - break; - } + mode = Selection+1; } if (hDown & KEY_TOUCH) { @@ -346,21 +334,12 @@ void Settings::SubMenuLogic(u32 hDown, u32 hHeld, touchPosition touch) { } } - if (hDown & KEY_B) { + if ((hDown & KEY_B) || (hDown & KEY_TOUCH && touching(touch, arrowPos[2]))) { Screen::back(); return; } - if (hDown & KEY_TOUCH && touching(touch, arrowPos[2])) { - Screen::back(); - return; - } - - if (hDown & KEY_TOUCH && touching(touch, arrowPos[4])) { - mode = 4; - } - - if (hDown & KEY_R) { + if ((hDown & KEY_R) || (hDown & KEY_TOUCH && touching(touch, arrowPos[4]))) { mode = 4; } } @@ -410,11 +389,7 @@ void Settings::LanguageSelection(u32 hDown, touchPosition touch) { } } - if (hDown & KEY_B) { - mode = 0; - } - - if (hDown & KEY_TOUCH && touching(touch, arrowPos[2])) { + if ((hDown & KEY_B) || (hDown & KEY_TOUCH && touching(touch, arrowPos[2]))) { mode = 0; } } @@ -426,7 +401,7 @@ void Settings::colorChanging(u32 hDown, touchPosition touch) { int blue; if (hDown & KEY_TOUCH) { - for (int i = 0; i < 7; i++) { + for (int i = 0; i < 8; i++) { if(touch.px > 54 + i * 25 && touch.px < 54 + i * 25+16 && touch.py > 2 && touch.py < 2+16) { colorMode = i; } @@ -434,28 +409,16 @@ void Settings::colorChanging(u32 hDown, touchPosition touch) { } - if (hDown & KEY_B) { + if ((hDown & KEY_B) || (hDown & KEY_TOUCH && touching(touch, arrowPos[2]))) { mode = 0; } - if (hDown & KEY_TOUCH && touching(touch, arrowPos[2])) { - mode = 0; - } - - if (hDown & KEY_TOUCH && touching(touch, arrowPos[0])) { + if ((hDown & KEY_L || hDown & KEY_LEFT) || (hDown & KEY_TOUCH && touching(touch, arrowPos[0]))) { if(colorMode > 0) colorMode--; } - if (hDown & KEY_L || hDown & KEY_LEFT) { - if(colorMode > 0) colorMode--; - } - - if (hDown & KEY_TOUCH && touching(touch, arrowPos[1])) { - if(colorMode < 6) colorMode++; - } - - if (hDown & KEY_R || hDown & KEY_RIGHT) { - if(colorMode < 6) colorMode++; + if ((hDown & KEY_R || hDown & KEY_RIGHT) || (hDown & KEY_TOUCH && touching(touch, arrowPos[1]))) { + if(colorMode < 7) colorMode++; } if (hDown & KEY_TOUCH) { @@ -481,7 +444,7 @@ void Settings::colorChanging(u32 hDown, touchPosition touch) { } - } else if (touching(touch, buttons[1])) { + } else if (touching(touch, buttons[1]) && colorMode != 7) { int temp = Input::getUint(255, Lang::get("ENTER_GREEN_RGB")); if(temp != -1) { green = temp; @@ -521,6 +484,9 @@ void Settings::colorChanging(u32 hDown, touchPosition touch) { Config::progressbarColor = RGBA8(ColorHelper::getColorValue(Config::progressbarColor, 2), ColorHelper::getColorValue(Config::progressbarColor, 1), blue, 255); } } + } else if (touching(touch, buttons[1]) && colorMode == 7) { + if (Config::UseBars == true) Config::UseBars = false; + else if (Config::UseBars == false) Config::UseBars = true; } } } diff --git a/source/screens/tinyDB.cpp b/source/screens/tinyDB.cpp deleted file mode 100644 index ae59cb0..0000000 --- a/source/screens/tinyDB.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* -* This file is part of Universal-Updater -* Copyright (C) 2019 DeadPhoenix8091, Epicpkmn11, Flame, RocketRobz, StackZ, TotallyNotGuy -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -* Additional Terms 7.b and 7.c of GPLv3 apply to this file: -* * Requiring preservation of specified reasonable legal notices or -* author attributions in that material or in the Appropriate Legal -* Notices displayed by works containing it. -* * Prohibiting misrepresentation of the origin of that material, -* or requiring that modified versions of such material be marked in -* reasonable ways as different from the original version. -*/ - -#include "download/download.hpp" - -#include "screens/tinyDB.hpp" - -#include "utils/config.hpp" -#include "utils/fileBrowse.h" -#include "utils/json.hpp" -#include "utils/formatting.hpp" -#include "utils/scriptHelper.hpp" - -extern bool touching(touchPosition touch, Structs::ButtonPos button); -#define ENTRIES_PER_SCREEN 3 -#define ENTRIES_PER_LIST 7 - -// JSON file for TinyDB. -nlohmann::json tinyDBJson; -std::string selectedOption; - -// For the Bar Textures. -extern C2D_SpriteSheet sprites; - -#define tinyDBFile "sdmc:/3ds/Universal-Updater/TinyDB.json" - -std::string maxEntries; - -// Parse the Objects. -std::vector parseObjects() { - FILE* file = fopen(tinyDBFile, "rt"); - if(!file) { - printf("File not found\n"); - return {{""}}; - } - tinyDBJson = nlohmann::json::parse(file, nullptr, false); - fclose(file); - - std::vector objs; - for(auto it = tinyDBJson.begin();it != tinyDBJson.end(); it++) { - if(it.key() != "info") { - objs.push_back(it.key()); - } - } - return objs; -} - -std::vector tinyDBList; - -TinyDB::TinyDB() { - DisplayMsg(Lang::get("TINYDB_DOWNLOADING")); - downloadToFile("https://tinydb.eiphax.tech/api/universal-updater.json?raw=true", tinyDBFile); - tinyDBList = parseObjects(); - selectedOption = tinyDBList[0]; -} - -void TinyDB::Draw(void) const { - std::string entryAmount = std::to_string(selection+1) + " / " + std::to_string(tinyDBList.size()); - std::string info; - Gui::setDraw(top); - Gui::Draw_Rect(0, 0, 400, 25, C2D_Color32(63, 81, 181, 255)); - Gui::Draw_Rect(0, 25, 400, 190, C2D_Color32(140, 140, 140, 255)); - Gui::Draw_Rect(0, 215, 400, 25, C2D_Color32(63, 81, 181, 255)); - - if (Config::UseBars == true) { - Gui::sprite(sprites_top_screen_top_idx, 0, 0); - Gui::sprite(sprites_top_screen_bot_idx, 0, 215); - Gui::DrawStringCentered(0, 0, 0.7f, Config::TxtColor, "TinyDB", 400); - Gui::DrawString(397-Gui::GetStringWidth(0.6f, entryAmount), 239-Gui::GetStringHeight(0.6f, entryAmount), 0.6f, Config::TxtColor, entryAmount); - } else { - Gui::DrawStringCentered(0, 2, 0.7f, Config::TxtColor, "TinyDB", 400); - Gui::DrawString(397-Gui::GetStringWidth(0.6f, entryAmount), 237-Gui::GetStringHeight(0.6f, entryAmount), 0.6f, Config::TxtColor, entryAmount); - } - - Gui::DrawStringCentered(0, 35, 0.6f, Config::TxtColor, Lang::get("AUTHOR") + std::string(tinyDBJson[selectedOption]["info"]["author"]), 400); - Gui::DrawStringCentered(0, 65, 0.6f, Config::TxtColor, Lang::get("DESC") + std::string(tinyDBJson[selectedOption]["info"]["description"]), 400); - Gui::DrawStringCentered(0, 95, 0.6f, Config::TxtColor, Lang::get("RELEASE_TAG") + std::string(tinyDBJson[selectedOption]["info"]["releaseTag"]), 400); - Gui::DrawStringCentered(0, 125, 0.6f, Config::TxtColor, Lang::get("RELEASE_ID") + std::string(tinyDBJson[selectedOption]["info"]["releaseId"]), 400); - Gui::DrawStringCentered(0, 155, 0.6f, Config::TxtColor, Lang::get("TITLE_ID") + std::string(tinyDBJson[selectedOption]["info"]["titleid"]), 400); - Gui::DrawStringCentered(0, 185, 0.6f, Config::TxtColor, Lang::get("FILE_SIZE") + formatBytes(int64_t(tinyDBJson[selectedOption]["info"]["fileSize"])), 400); - - - Gui::setDraw(bottom); - Gui::Draw_Rect(0, 0, 320, 25, C2D_Color32(63, 81, 181, 255)); - Gui::Draw_Rect(0, 25, 320, 190, C2D_Color32(140, 140, 140, 255)); - Gui::Draw_Rect(0, 215, 320, 25, C2D_Color32(63, 81, 181, 255)); - if (Config::UseBars == true) { - Gui::sprite(sprites_bottom_screen_top_idx, 0, 0); - Gui::sprite(sprites_bottom_screen_bot_idx, 0, 215); - } - - Gui::DrawArrow(295, -1); - Gui::DrawArrow(315, 240, 180.0); - Gui::DrawArrow(0, 218, 0, 1); - Gui::spriteBlend(sprites_view_idx, arrowPos[3].x, arrowPos[3].y); -// Gui::spriteBlend(sprites_search_idx, arrowPos[4].x, arrowPos[4].y); - - if (Config::viewMode == 0) { - for(int i=0;i 0) { - selection--; - selectedOption = tinyDBList[selection]; - } else { - selection = (int)tinyDBList.size()-1; - selectedOption = tinyDBList[selection]; - } - } - - if (hDown & KEY_TOUCH && touching(touch, arrowPos[1])) { - if (selection < (int)tinyDBList.size()-1) { - selection++; - selectedOption = tinyDBList[selection]; - } else { - selection = 0; - selectedOption = tinyDBList[selection]; - } - } - - if (hDown & KEY_TOUCH && touching(touch, arrowPos[2])) { - Screen::back(); - return; - } - - if (hHeld & KEY_UP && !keyRepeatDelay) { - if (selection > 0) { - selection--; - selectedOption = tinyDBList[selection]; - } else { - selection = (int)tinyDBList.size()-1; - selectedOption = tinyDBList[selection]; - } - if (fastMode == true) { - keyRepeatDelay = 3; - } else if (fastMode == false){ - keyRepeatDelay = 6; - } - } - - if (hHeld & KEY_DOWN && !keyRepeatDelay) { - if (selection < (int)tinyDBList.size()-1) { - selection++; - selectedOption = tinyDBList[selection]; - } else { - selection = 0; - selectedOption = tinyDBList[selection]; - } - if (fastMode == true) { - keyRepeatDelay = 3; - } else if (fastMode == false){ - keyRepeatDelay = 6; - } - } - - if (Config::viewMode == 0) { - if(selection < screenPos) { - screenPos = selection; - } else if (selection > screenPos + ENTRIES_PER_SCREEN - 1) { - screenPos = selection - ENTRIES_PER_SCREEN + 1; - } - } else if (Config::viewMode == 1) { - if(selection < screenPosList) { - screenPosList = selection; - } else if (selection > screenPosList + ENTRIES_PER_LIST - 1) { - screenPosList = selection - ENTRIES_PER_LIST + 1; - } - } - - if (hDown & KEY_X || hDown & KEY_TOUCH && touching(touch, arrowPos[3])) { - if (Config::viewMode == 0) { - Config::viewMode = 1; - } else { - Config::viewMode = 0; - } - } - - if (hDown & KEY_TOUCH) { - if (Config::viewMode == 0) { - for(int i=0;i 40+(i*57) && touch.py < 40+(i*57)+45) { - selection = screenPos + i; - selectedOption = tinyDBList[screenPos + i]; - execute(); - } - } - } else if (Config::viewMode == 1) { - for(int i=0;i (i+1)*27 && touch.py < (i+2)*27) { - selection = screenPosList + i; - selectedOption = tinyDBList[screenPosList + i]; - execute(); - } - } - } - } - - if (hDown & KEY_A) { - execute(); - } -} - -void TinyDB::execute() { - for(int i=0;i<(int)tinyDBJson.at(selectedOption).at("script").size();i++) { - std::string type = tinyDBJson.at(selectedOption).at("script").at(i).at("type"); - if(type == "deleteFile") { - bool missing = false; - std::string file, message; - if(tinyDBJson.at(selectedOption).at("script").at(i).contains("file")) file = tinyDBJson.at(selectedOption).at("script").at(i).at("file"); - else missing = true; - if(tinyDBJson.at(selectedOption).at("script").at(i).contains("message")) message = tinyDBJson.at(selectedOption).at("script").at(i).at("message"); - if(!missing) ScriptHelper::removeFile(file, message); - - } else if(type == "downloadFile") { - bool missing = false; - std::string file, output, message; - if(tinyDBJson.at(selectedOption).at("script").at(i).contains("file")) file = tinyDBJson.at(selectedOption).at("script").at(i).at("file"); - else missing = true; - if(tinyDBJson.at(selectedOption).at("script").at(i).contains("output")) output = tinyDBJson.at(selectedOption).at("script").at(i).at("output"); - else missing = true; - if(tinyDBJson.at(selectedOption).at("script").at(i).contains("message")) message = tinyDBJson.at(selectedOption).at("script").at(i).at("message"); - if(!missing) ScriptHelper::downloadFile(file, output, message); - - } else if(type == "installCia") { - bool missing = false; - std::string file, message; - if(tinyDBJson.at(selectedOption).at("script").at(i).contains("file")) file = tinyDBJson.at(selectedOption).at("script").at(i).at("file"); - else missing = true; - if(tinyDBJson.at(selectedOption).at("script").at(i).contains("message")) message = tinyDBJson.at(selectedOption).at("script").at(i).at("message"); - if(!missing) ScriptHelper::installFile(file, message); - } - } - doneMsg(); -} \ No newline at end of file diff --git a/source/screens/unistore.cpp b/source/screens/unistore.cpp new file mode 100644 index 0000000..72180fb --- /dev/null +++ b/source/screens/unistore.cpp @@ -0,0 +1,760 @@ +/* +* This file is part of Universal-Updater +* Copyright (C) 2019 DeadPhoenix8091, Epicpkmn11, Flame, RocketRobz, StackZ, TotallyNotGuy +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. +*/ + +#include "keyboard.hpp" + +#include "download/download.hpp" + +#include "screens/unistore.hpp" + +#include "utils/config.hpp" +#include "utils/fileBrowse.h" +#include "utils/formatting.hpp" +#include "utils/json.hpp" +#include "utils/scriptHelper.hpp" + +#include +#include +#include + +extern bool touching(touchPosition touch, Structs::ButtonPos button); +extern u32 getColor(std::string colorString); +nlohmann::json appStoreJson; +std::string currentStoreFile; +extern bool isScriptSelected; + +extern u32 barColor; +extern u32 bgTopColor; +extern u32 bgBottomColor; +extern u32 TextColor; +extern u32 progressBar; +extern u32 selected; +extern u32 unselected; + +C2D_SpriteSheet appStoreSheet; + +struct storeInfo2 { + std::string title; + std::string author; + std::string description; + std::string url; + std::string file; + std::string storeSheet; + std::string sheetURL; +}; + +extern void notImplemented(void); + +// Parse informations like URL, Title, Author, Description. +storeInfo2 parseStoreInfo(std::string fileName) { + FILE* file = fopen(fileName.c_str(), "rt"); + if(!file) { + printf("File not found\n"); + return {"", ""}; + } + nlohmann::json json = nlohmann::json::parse(file, nullptr, false); + fclose(file); + + storeInfo2 info; + info.title = ScriptHelper::getString(json, "storeInfo", "title"); + info.author = ScriptHelper::getString(json, "storeInfo", "author"); + info.description = ScriptHelper::getString(json, "storeInfo", "description"); + info.url = ScriptHelper::getString(json, "storeInfo", "url"); + info.file = ScriptHelper::getString(json, "storeInfo", "file"); + info.storeSheet = ScriptHelper::getString(json, "storeInfo", "sheet"); + info.sheetURL = ScriptHelper::getString(json, "storeInfo", "sheetURL"); + return info; +} + +nlohmann::json openStoreFile() { + FILE* file = fopen(currentStoreFile.c_str(), "rt"); + nlohmann::json jsonFile; + if(file) jsonFile = nlohmann::json::parse(file, nullptr, false); + fclose(file); + return jsonFile; +} + +// Parse the Objects. +std::vector parseStoreObjects(std::string storeName) { + FILE* file = fopen(storeName.c_str(), "rt"); + if(!file) { + printf("File not found\n"); + return {{""}}; + } + nlohmann::json json = nlohmann::json::parse(file, nullptr, false); + fclose(file); + + std::vector objs; + for(auto it = json.begin();it != json.end(); it++) { + if(it.key() != "storeInfo") { + objs.push_back(it.key()); + } + } + return objs; +} + +std::vector storeInfo; // Store selection. +std::vector appStoreList; // Actual store. ;P +std::vector descLines; +std::string storeDesc = ""; + +bool sheetHasLoaded = false; +// Sheet / Icon stuff. +void loadStoreSheet(int pos) { + appStoreSheet = C2D_SpriteSheetLoad(storeInfo[pos].storeSheet.c_str()); + sheetHasLoaded = true; +} +void freeSheet() { + C2D_SpriteSheetFree(appStoreSheet); + sheetHasLoaded = false; +} + +void UniStore::descript() { + if (storeInfo[selection].description != "" || storeInfo[selection].description != "MISSING: storeInfo.description") { + storeDesc = storeInfo[selection].description; + } else storeDesc = ""; +} + +void loadStoreDesc(void) { + descLines.clear(); + while(storeDesc.find('\n') != storeDesc.npos) { + descLines.push_back(storeDesc.substr(0, storeDesc.find('\n'))); + storeDesc = storeDesc.substr(storeDesc.find('\n')+1); + } + descLines.push_back(storeDesc.substr(0, storeDesc.find('\n'))); +} + +UniStore::UniStore() { + dirContents.clear(); + chdir(Config::StorePath.c_str()); + getDirectoryContents(dirContents, {"unistore"}); + for(uint i=0;i Storelist. +void UniStore::DrawStoreList(void) const { + std::string line1; + std::string line2; + std::string storeAmount = std::to_string(selection +1) + " / " + std::to_string(storeInfo.size()); + Gui::DrawTop(); + if (Config::UseBars == true) { + Gui::DrawStringCentered(0, 0, 0.7f, Config::TxtColor, storeInfo[selection].title, 400); + Gui::DrawString(397-Gui::GetStringWidth(0.6f, storeAmount), 239-Gui::GetStringHeight(0.6f, storeAmount), 0.6f, Config::TxtColor, storeAmount); + } else { + Gui::DrawStringCentered(0, 2, 0.7f, Config::TxtColor, storeInfo[selection].title, 400); + Gui::DrawString(397-Gui::GetStringWidth(0.6f, storeAmount), 237-Gui::GetStringHeight(0.6f, storeAmount), 0.6f, Config::TxtColor, storeAmount); + } + for(uint i=0;i 0) { + selection--; + descript(); + loadStoreDesc(); + } else { + selection = (int)storeInfo.size()-1; + descript(); + loadStoreDesc(); + } + if (fastMode == true) { + keyRepeatDelay = 3; + } else if (fastMode == false){ + keyRepeatDelay = 6; + } + } + + if ((hDown & KEY_Y) || (hDown & KEY_TOUCH && touching(touch, arrowPos[5]))) { + if (Gui::promptMsg(Lang::get("WOULD_YOU_LIKE_UPDATE"))) { + if(storeInfo[selection].url != "" && storeInfo[selection].url != "MISSING: storeInfo.url" && + storeInfo[selection].file != "" && storeInfo[selection].file != "MISSING: storeInfo.file") { + ScriptHelper::downloadFile(storeInfo[selection].url, storeInfo[selection].file, Lang::get("UPDATING")); + } + if(storeInfo[selection].sheetURL != "" && storeInfo[selection].sheetURL != "MISSING: storeInfo.sheetURL" && + storeInfo[selection].storeSheet != "" && storeInfo[selection].storeSheet != "MISSING: storeInfo.sheet") { + ScriptHelper::downloadFile(storeInfo[selection].sheetURL, storeInfo[selection].storeSheet, Lang::get("UPDATING")); + } + // Refresh the list. + dirContents.clear(); + storeInfo.clear(); + chdir(Config::StorePath.c_str()); + getDirectoryContents(dirContents, {"unistore"}); + for(uint i=0;i screenPos + ENTRIES_PER_SCREEN - 1) { + screenPos = selection - ENTRIES_PER_SCREEN + 1; + } + } else if (Config::viewMode == 1) { + if(selection < screenPosList) { + screenPosList = selection; + } else if (selection > screenPosList + ENTRIES_PER_LIST - 1) { + screenPosList = selection - ENTRIES_PER_LIST + 1; + } + } + + if (hDown & KEY_TOUCH) { + if (Config::viewMode == 0) { + for(int i=0;i 40+(i*57) && touch.py < 40+(i*57)+45) { + if (ScriptHelper::checkIfValid(dirContents[screenPos + i].name, 1) == true) { + currentStoreFile = dirContents[screenPos + i].name; + DisplayMsg(Lang::get("PREPARE_STORE")); + if (storeInfo[screenPos + i].storeSheet != "" || storeInfo[screenPos + i].storeSheet != "MISSING: storeInfo.sheet") { + if(access(storeInfo[screenPos + i].storeSheet.c_str(), F_OK) != -1 ) { + loadStoreSheet(screenPos + i); + } + } + appStoreJson = openStoreFile(); + appStoreList = parseStoreObjects(currentStoreFile); + loadStoreColors(appStoreJson); + selectedOptionAppStore = appStoreList[0]; + isScriptSelected = true; + mode = 1; + } + } + } + } else if (Config::viewMode == 1) { + for(int i=0;i (i+1)*27 && touch.py < (i+2)*27) { + if (ScriptHelper::checkIfValid(dirContents[screenPosList + i].name, 1) == true) { + currentStoreFile = dirContents[screenPosList + i].name; + DisplayMsg(Lang::get("PREPARE_STORE")); + if (storeInfo[screenPosList + i].storeSheet != "" || storeInfo[screenPosList + i].storeSheet != "MISSING: storeInfo.sheet") { + if(access(storeInfo[screenPosList + i].storeSheet.c_str(), F_OK) != -1 ) { + loadStoreSheet(screenPosList + i); + } + } + appStoreJson = openStoreFile(); + appStoreList = parseStoreObjects(currentStoreFile); + loadStoreColors(appStoreJson); + selectedOptionAppStore = appStoreList[0]; + isScriptSelected = true; + mode = 1; + } + } + } + } + } +} + +void UniStore::StoreLogic(u32 hDown, u32 hHeld, touchPosition touch) { + if (keyRepeatDelay) keyRepeatDelay--; + + if ((hDown & KEY_B) || (hDown & KEY_TOUCH && touching(touch, arrowPos[2]))) { + mode = 0; + appStoreList.clear(); + isScriptSelected = false; + selection2 = 0; + if (sheetHasLoaded == true) { + freeSheet(); + } + } + + if (hDown & KEY_R) { + fastMode = true; + } + + if (hDown & KEY_L) { + fastMode = false; + } + + // Go one entry up. + if ((hHeld & KEY_UP && !keyRepeatDelay) || (hDown & KEY_TOUCH && touching(touch, arrowPos[0]))) { + if (selection2 > 0) { + selection2--; + selectedOptionAppStore = appStoreList[selection2]; + } else { + selection2 = (int)appStoreList.size()-1; + selectedOptionAppStore = appStoreList[selection2]; + } + if (fastMode == true) { + keyRepeatDelay = 3; + } else if (fastMode == false){ + keyRepeatDelay = 6; + } + } + + // Go one entry down. + if ((hHeld & KEY_DOWN && !keyRepeatDelay) || (hDown & KEY_TOUCH && touching(touch, arrowPos[1]))) { + if (selection2 < (int)appStoreList.size()-1) { + selection2++; + selectedOptionAppStore = appStoreList[selection2]; + } else { + selection2 = 0; + selectedOptionAppStore = appStoreList[selection2]; + } + if (fastMode == true) { + keyRepeatDelay = 3; + } else if (fastMode == false){ + keyRepeatDelay = 6; + } + } + + // Execute touched Entry. + if (hDown & KEY_TOUCH) { + if (Config::viewMode == 0) { + for(int i=0;i 40+(i*57) && touch.py < 40+(i*57)+45) { + selection2 = screenPos2 + i; + selectedOptionAppStore = appStoreList[screenPos2 + i]; + execute(); + } + } + } else if (Config::viewMode == 1) { + for(int i=0;i (i+1)*27 && touch.py < (i+2)*27) { + selection2 = screenPosList2 + i; + selectedOptionAppStore = appStoreList[screenPosList2 + i]; + execute(); + } + } + } + } + // Execute that Entry. + if (hDown & KEY_A) { + execute(); + } + + if (Config::viewMode == 0) { + if(selection2 < screenPos2) { + screenPos2 = selection2; + } else if (selection2 > screenPos2 + ENTRIES_PER_SCREEN - 1) { + screenPos2 = selection2 - ENTRIES_PER_SCREEN + 1; + } + } else if (Config::viewMode == 1) { + if(selection2 < screenPosList2) { + screenPosList2 = selection2; + } else if (selection2 > screenPosList2 + ENTRIES_PER_LIST - 1) { + screenPosList2 = selection2 - ENTRIES_PER_LIST + 1; + } + } +} + +void UniStore::Logic(u32 hDown, u32 hHeld, touchPosition touch) { + if (mode == 0) { + StoreSelectionLogic(hDown, hHeld, touch); + } else if (mode == 1) { + StoreLogic(hDown, hHeld, touch); + } else if (mode == 2) { + SearchLogic(hDown, hHeld, touch); + } + + // Switch ViewMode. + if (((mode != 2) && (hDown & KEY_X)) || ((mode != 2) && (hDown & KEY_TOUCH && touching(touch, arrowPos[3])))) { + if (Config::viewMode == 0) { + Config::viewMode = 1; + } else { + Config::viewMode = 0; + } + } +} + +// Execute Entry. +void UniStore::execute() { + for(int i=0;i<(int)appStoreJson.at(selectedOptionAppStore).at("script").size();i++) { + std::string type = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("type"); + if(type == "deleteFile") { + bool missing = false; + std::string file, message; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("file")) file = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("file"); + else missing = true; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("message")) message = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("message"); + if(!missing) ScriptHelper::removeFile(file, message); + + } else if(type == "downloadFile") { + bool missing = false; + std::string file, output, message; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("file")) file = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("file"); + else missing = true; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("output")) output = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("output"); + else missing = true; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("message")) message = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("message"); + if(!missing) ScriptHelper::downloadFile(file, output, message); + + } else if(type == "downloadRelease") { + bool missing = false, includePrereleases = false; + std::string repo, file, output, message; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("repo")) repo = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("repo"); + else missing = true; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("file")) file = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("file"); + else missing = true; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("output")) output = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("output"); + else missing = true; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("includePrereleases") && appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("includePrereleases").is_boolean()) + includePrereleases = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("includePrereleases"); + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("message")) message = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("message"); + if(!missing) ScriptHelper::downloadRelease(repo, file, output, includePrereleases, message); + + } else if(type == "extractFile") { + bool missing = false; + std::string file, input, output, message; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("file")) file = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("file"); + else missing = true; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("input")) input = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("input"); + else missing = true; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("output")) output = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("output"); + else missing = true; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("message")) message = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("message"); + if(!missing) ScriptHelper::extractFile(file, input, output, message); + + } else if(type == "installCia") { + bool missing = false; + std::string file, message; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("file")) file = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("file"); + else missing = true; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("message")) message = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("message"); + if(!missing) ScriptHelper::installFile(file, message); + + } else if (type == "mkdir") { + bool missing = false; + std::string directory, message; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("directory")) directory = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("directory"); + else missing = true; + if(!missing) makeDirs(directory.c_str()); + + } else if (type == "rmdir") { + bool missing = false; + std::string directory, message, promptmsg; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("directory")) directory = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("directory"); + else missing = true; + promptmsg = Lang::get("DELETE_PROMPT") + "\n" + directory; + if(!missing) { + if (Gui::promptMsg(promptmsg)) { + removeDirRecursive(directory.c_str()); + } + } + + } else if (type == "mkfile") { + bool missing = false; + std::string file; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("file")) file = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("file"); + else missing = true; + if(!missing) ScriptHelper::createFile(file.c_str()); + + } else if (type == "timeMsg") { + bool missing = false; + std::string message; + int seconds; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("message")) message = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("message"); + else missing = true; + if(appStoreJson.at(selectedOptionAppStore).at("script").at(i).contains("seconds") && appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("seconds").is_number()) + seconds = appStoreJson.at(selectedOptionAppStore).at("script").at(i).at("seconds"); + else missing = true; + if(!missing) ScriptHelper::displayTimeMsg(message, seconds); + } else if (type == "saveConfig") { + Config::save(); + } else if (type == "notImplemented") { + notImplemented(); + } + } + doneMsg(); +} + +void UniStore::DrawSearch(void) const { + Gui::DrawTop(); + if (Config::UseBars == true) { + Gui::DrawStringCentered(0, 0, 0.7f, Config::TxtColor, Lang::get("UNISTORE_SEARCH"), 400); + } else { + Gui::DrawStringCentered(0, 2, 0.7f, Config::TxtColor, Lang::get("UNISTORE_SEARCH"), 400); + } + + Gui::sprite(sprites_uniStore_HD_idx, 140, 50, 0.2, 0.2); + Gui::DrawBottom(); + Gui::DrawArrow(0, 218, 0, 1); + + for (int i = 0; i < 2; i++) { + if (searchSelection == i) { + Gui::Draw_Rect(URLBtn[i].x, URLBtn[i].y, URLBtn[i].w, URLBtn[i].h, Config::SelectedColor); + } else { + Gui::Draw_Rect(URLBtn[i].x, URLBtn[i].y, URLBtn[i].w, URLBtn[i].h, Config::UnselectedColor); + } + } + Gui::DrawString((320-Gui::GetStringWidth(0.6f, Lang::get("FULL_URL")))/2-150+70, 110, 0.6f, Config::TxtColor, Lang::get("FULL_URL"), 140); + Gui::DrawString((320-Gui::GetStringWidth(0.6f, Lang::get("GITHUB")))/2+150-70, 110, 0.6f, Config::TxtColor, Lang::get("GITHUB"), 140); +} + +void UniStore::SearchLogic(u32 hDown, u32 hHeld, touchPosition touch) { + if ((hDown & KEY_B) || (hDown & KEY_TOUCH && touching(touch, arrowPos[2]))) { + // Refresh the list. + dirContents.clear(); + storeInfo.clear(); + chdir(Config::StorePath.c_str()); + getDirectoryContents(dirContents, {"unistore"}); + for(uint i=0;i buttonPositions = { {80, 220, 50, 15, -1}, // Select. {145, 220, 50, 15, -1}, // Refresh. {210, 220, 50, 15, -1}, // Back. + {0, 0, 25, 25, -1}, // ViewMode Change. }; /** @@ -198,7 +200,10 @@ std::string selectFilePath(std::string selectText, const std::vector dirContents; + std::string dirs; while (1) { Gui::clearTextBufs(); @@ -215,21 +220,28 @@ std::string selectFilePath(std::string selectText, const std::vector screenPos + ENTRIES_PER_SCREEN - 1) { + screenPos = selectedFile - ENTRIES_PER_SCREEN + 1; + } + } else if (Config::viewMode == 1) { + if(selectedFile < screenPosList) { + screenPosList = selectedFile; + } else if (selectedFile > screenPosList + ENTRIES_PER_LIST - 1) { + screenPosList = selectedFile - ENTRIES_PER_LIST + 1; + } + } } } \ No newline at end of file diff --git a/source/utils/scriptHelper.cpp b/source/utils/scriptHelper.cpp index f2f6dfa..0b2558f 100644 --- a/source/utils/scriptHelper.cpp +++ b/source/utils/scriptHelper.cpp @@ -133,7 +133,7 @@ void ScriptHelper::displayTimeMsg(std::string message, int seconds) { } } -bool ScriptHelper::checkIfValid(std::string scriptFile) { +bool ScriptHelper::checkIfValid(std::string scriptFile, int mode) { FILE* file = fopen(scriptFile.c_str(), "rt"); if(!file) { printf("File not found\n"); @@ -142,7 +142,11 @@ bool ScriptHelper::checkIfValid(std::string scriptFile) { nlohmann::json json = nlohmann::json::parse(file, nullptr, false); fclose(file); - if (!json.contains("info")) return false; + if (mode == 0) { + if (!json.contains("info")) return false; + } else if (mode == 1) { + if (!json.contains("storeInfo")) return false; + } return true; } \ No newline at end of file