diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 284909a..e4ad965 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: Build Universal-Updater on: push: - branches-ignore: [translation, full-rewrite, PNG] + branches-ignore: [translation] paths-ignore: - 'README.md' pull_request: diff --git a/.gitignore b/.gitignore index 0183c25..931fee6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,16 +6,16 @@ *.elf *.cia *.3dsx -*/build +*build *.map *.lst -.vscode/ipch +.vscode *.DS_Store romfs/gfx/*.t3x +include/version.hpp bannertool* makerom* *.pfs0 *.nso *.nacp -build/sprites.h diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 97d6069..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "files.associations": { - "*.tcc": "cpp", - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "exception": "cpp", - "fstream": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "memory": "cpp", - "new": "cpp", - "ostream": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "typeinfo": "cpp", - "valarray": "cpp", - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "cstdint": "cpp", - "deque": "cpp", - "forward_list": "cpp", - "map": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "optional": "cpp", - "random": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "initializer_list": "cpp", - "bitset": "cpp", - "chrono": "cpp", - "condition_variable": "cpp", - "ratio": "cpp", - "regex": "cpp", - "shared_mutex": "cpp" - } -} \ No newline at end of file diff --git a/Makefile b/Makefile index 8b2cbed..1d270b0 100644 --- a/Makefile +++ b/Makefile @@ -46,11 +46,22 @@ endif CURRENT_VERSION := $(shell git describe --abbrev=0 --tags) -# If on a tagged commit, use the tag instead of the commit +# If on a tagged commit, use just the tag ifneq ($(shell echo $(shell git tag -l --points-at HEAD) | head -c 1),) GIT_VER := $(shell git tag -l --points-at HEAD) else -GIT_VER := $(shell git describe --abbrev=0 --tags)-$(shell git rev-parse --short HEAD) +GIT_VER := $(shell git describe --abbrev=0 --tags)-$(shell git rev-parse --short=7 HEAD) +endif + +# Ensure version.hpp exists +ifeq (,$(wildcard include/version.hpp)) +$(shell mkdir -p include) +$(shell touch include/version.hpp) +endif + +# Print new version if changed +ifeq (,$(findstring $(GIT_VER), $(shell cat include/version.hpp))) +$(shell printf "#ifndef VERSION_HPP\n#define VERSION_HPP\n\n#define VER_NUMBER \"$(GIT_VER)\"\n\n#endif\n" > include/version.hpp) endif #--------------------------------------------------------------------------------- @@ -78,8 +89,8 @@ endif TARGET := Universal-Updater BUILD := build UNIVCORE := Universal-Core -SOURCES := $(UNIVCORE) source source/download source/gui source/lang source/overlays source/qr source/screens \ - source/store source/utils +SOURCES := $(UNIVCORE) source source/download source/gui source/lang source/menu source/overlays \ + source/qr source/screens source/store source/utils DATA := data INCLUDES := $(UNIVCORE) include include/download include/gui include/lang include/overlays include/qr include/screens \ include/store include/utils @@ -99,7 +110,6 @@ RSF_FILE := app/build-cia.rsf ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft CFLAGS := -g -Wall -Wno-psabi -O2 -mword-relocations \ - -DV_STRING=\"$(GIT_VER)\" \ -DC_V=\"$(CURRENT_VERSION)\" \ -fomit-frame-pointer -ffunction-sections \ $(ARCH) diff --git a/assets/gfx/sprites.t3s b/assets/gfx/sprites.t3s index 301e1e0..eef3353 100644 --- a/assets/gfx/sprites.t3s +++ b/assets/gfx/sprites.t3s @@ -3,15 +3,33 @@ sprites/add.png sprites/add_font.png sprites/arrow.png +sprites/battery/battery_0.png +sprites/battery/battery_1.png +sprites/battery/battery_2.png +sprites/battery/battery_3.png +sprites/battery/battery_4.png +sprites/battery/battery_blink.png +sprites/battery/battery_charge.png +sprites/battery/battery_charge_full.png +sprites/cancel.png sprites/checked.png sprites/delete.png sprites/download.png sprites/info.png +sprites/installed.png sprites/keyboard.png sprites/list.png sprites/noIcon.png sprites/notes.png sprites/qr_code.png +sprites/queue0.png +sprites/queue1.png +sprites/queue2.png +sprites/queue3.png +sprites/queue4.png +sprites/queue5.png +sprites/queue6.png +sprites/queue7.png sprites/screenshot.png sprites/search.png sprites/settings.png diff --git a/assets/gfx/sprites/battery/battery_0.png b/assets/gfx/sprites/battery/battery_0.png new file mode 100644 index 0000000..628de22 Binary files /dev/null and b/assets/gfx/sprites/battery/battery_0.png differ diff --git a/assets/gfx/sprites/battery/battery_1.png b/assets/gfx/sprites/battery/battery_1.png new file mode 100644 index 0000000..2d2185e Binary files /dev/null and b/assets/gfx/sprites/battery/battery_1.png differ diff --git a/assets/gfx/sprites/battery/battery_2.png b/assets/gfx/sprites/battery/battery_2.png new file mode 100644 index 0000000..465c3dd Binary files /dev/null and b/assets/gfx/sprites/battery/battery_2.png differ diff --git a/assets/gfx/sprites/battery/battery_3.png b/assets/gfx/sprites/battery/battery_3.png new file mode 100644 index 0000000..7a40598 Binary files /dev/null and b/assets/gfx/sprites/battery/battery_3.png differ diff --git a/assets/gfx/sprites/battery/battery_4.png b/assets/gfx/sprites/battery/battery_4.png new file mode 100644 index 0000000..7cf311c Binary files /dev/null and b/assets/gfx/sprites/battery/battery_4.png differ diff --git a/assets/gfx/sprites/battery/battery_blink.png b/assets/gfx/sprites/battery/battery_blink.png new file mode 100644 index 0000000..3c287c2 Binary files /dev/null and b/assets/gfx/sprites/battery/battery_blink.png differ diff --git a/assets/gfx/sprites/battery/battery_charge.png b/assets/gfx/sprites/battery/battery_charge.png new file mode 100644 index 0000000..c8774ec Binary files /dev/null and b/assets/gfx/sprites/battery/battery_charge.png differ diff --git a/assets/gfx/sprites/battery/battery_charge_full.png b/assets/gfx/sprites/battery/battery_charge_full.png new file mode 100644 index 0000000..8b79ac7 Binary files /dev/null and b/assets/gfx/sprites/battery/battery_charge_full.png differ diff --git a/assets/gfx/sprites/cancel.png b/assets/gfx/sprites/cancel.png new file mode 100644 index 0000000..dba91e4 Binary files /dev/null and b/assets/gfx/sprites/cancel.png differ diff --git a/assets/gfx/sprites/installed.png b/assets/gfx/sprites/installed.png new file mode 100644 index 0000000..f2692c8 Binary files /dev/null and b/assets/gfx/sprites/installed.png differ diff --git a/assets/gfx/sprites/queue0.png b/assets/gfx/sprites/queue0.png new file mode 100644 index 0000000..cd9450e Binary files /dev/null and b/assets/gfx/sprites/queue0.png differ diff --git a/assets/gfx/sprites/queue1.png b/assets/gfx/sprites/queue1.png new file mode 100644 index 0000000..9781ca4 Binary files /dev/null and b/assets/gfx/sprites/queue1.png differ diff --git a/assets/gfx/sprites/queue2.png b/assets/gfx/sprites/queue2.png new file mode 100644 index 0000000..6f4bcd0 Binary files /dev/null and b/assets/gfx/sprites/queue2.png differ diff --git a/assets/gfx/sprites/queue3.png b/assets/gfx/sprites/queue3.png new file mode 100644 index 0000000..10a446a Binary files /dev/null and b/assets/gfx/sprites/queue3.png differ diff --git a/assets/gfx/sprites/queue4.png b/assets/gfx/sprites/queue4.png new file mode 100644 index 0000000..6d6be96 Binary files /dev/null and b/assets/gfx/sprites/queue4.png differ diff --git a/assets/gfx/sprites/queue5.png b/assets/gfx/sprites/queue5.png new file mode 100644 index 0000000..6e9ee3c Binary files /dev/null and b/assets/gfx/sprites/queue5.png differ diff --git a/assets/gfx/sprites/queue6.png b/assets/gfx/sprites/queue6.png new file mode 100644 index 0000000..aa886ed Binary files /dev/null and b/assets/gfx/sprites/queue6.png differ diff --git a/assets/gfx/sprites/queue7.png b/assets/gfx/sprites/queue7.png new file mode 100644 index 0000000..f56bc9e Binary files /dev/null and b/assets/gfx/sprites/queue7.png differ diff --git a/include/common.hpp b/include/common.hpp index 395d0e1..9ec1b19 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -27,15 +27,17 @@ #ifndef _UNIVERSAL_UPDATER_COMMON_HPP #define _UNIVERSAL_UPDATER_COMMON_HPP -#include <3ds.h> #include "config.hpp" #include "gfx.hpp" #include "lang.hpp" #include "msg.hpp" #include "screenCommon.hpp" +#include <3ds.h> +#include #define _STORE_PATH "sdmc:/3ds/Universal-Updater/stores/" #define _META_PATH "sdmc:/3ds/Universal-Updater/MetaData.json" +#define _THEME_AMOUNT 1 #define _UNISTORE_VERSION 4 inline std::unique_ptr config; diff --git a/include/gui/gfx.hpp b/include/gui/gfx.hpp index 21ce886..053a676 100644 --- a/include/gui/gfx.hpp +++ b/include/gui/gfx.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -32,50 +32,48 @@ #include #include -/* - Define all used Colors, for easier changes. -*/ - /* Standard Colors. */ #define WHITE C2D_Color32(255, 255, 255, 255) #define BLACK C2D_Color32(0, 0, 0, 255) #define TRANSPARENT C2D_Color32(0, 0, 0, 0) #define DIM_COLOR C2D_Color32(0, 0, 0, 190) -/* Bar, Text, BG Colors. */ -#define TEXT_COLOR WHITE -#define BAR_COLOR C2D_Color32(50, 73, 98, 255) -#define BAR_OUTL_COLOR C2D_Color32(25, 30, 53, 255) -#define BG_COLOR C2D_Color32(38, 44, 77, 255) - -/* Entry Colors. */ -#define ENTRY_BAR_COLOR BAR_COLOR -#define ENTRY_BAR_OUTL_COLOR BAR_OUTL_COLOR - -/* Entry Box Colors. */ -#define BOX_INSIDE_COLOR C2D_Color32(28, 33, 58, 255) -#define BOX_SELECTED_COLOR C2D_Color32(108, 130, 155, 255) -#define BOX_UNSELECTED_COLOR BLACK - -/* Progressbar Colors. */ -#define PROGRESSBAR_OUT_COLOR BOX_INSIDE_COLOR -#define PROGRESSBAR_IN_COLOR SIDEBAR_UNSELECTED_COLOR - -/* Search Menu Colors. */ -#define SEARCH_BAR_COLOR C2D_Color32(51, 75, 102, 255) -#define SEARCH_BAR_OUTL_COLOR BAR_OUTL_COLOR - -/* Sidebar Colors. */ -#define SIDEBAR_SELECTED_COLOR C2D_Color32(108, 130, 155, 255) -#define SIDEBAR_UNSELECTED_COLOR C2D_Color32(77, 101, 128, 255) +struct UITheme { + uint32_t BarColor; + uint32_t BGColor; + uint32_t BarOutline; + uint32_t TextColor; + uint32_t EntryBar; + uint32_t EntryOutline; + uint32_t BoxInside; + uint32_t BoxSelected; + uint32_t BoxUnselected; + uint32_t ProgressbarOut; + uint32_t ProgressbarIn; + uint32_t SearchBar; + uint32_t SearchbarOutline; + uint32_t SideBarSelected; + uint32_t SideBarUnselected; + /* NOTE: Also used for the buttons. */ + uint32_t MarkSelected; + uint32_t MarkUnselected; + uint32_t DownListPrev; + uint32_t SideBarIconColor; +}; namespace GFX { + extern std::vector Themes; + extern int SelectedTheme; + void DrawTop(void); void DrawBottom(); void DrawSprite(int img, int x, int y, float ScaleX = 1, float ScaleY = 1); - void DrawBox(float xPos, float yPos, float width = 50, float height = 50, bool selected = false, uint32_t clr = BOX_INSIDE_COLOR); + void DrawBox(float xPos, float yPos, float width = 50, float height = 50, bool selected = false, uint32_t clr = GFX::Themes[GFX::SelectedTheme].BoxInside); void DrawCheckbox(float xPos, float yPos, bool selected); void DrawToggle(float xPos, float yPos, bool toggled); + void DrawTime(); + void DrawBattery(); + void HandleBattery(); }; #endif \ No newline at end of file diff --git a/include/gui/msg.hpp b/include/gui/msg.hpp index ab38e99..0399524 100644 --- a/include/gui/msg.hpp +++ b/include/gui/msg.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/init.hpp b/include/init.hpp index 9cd8c64..8051d94 100644 --- a/include/init.hpp +++ b/include/init.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/keyboard.hpp b/include/keyboard.hpp index 67c9225..133bdc8 100644 --- a/include/keyboard.hpp +++ b/include/keyboard.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/overlays/overlay.hpp b/include/overlays/overlay.hpp index 2e1ff12..e727cdb 100644 --- a/include/overlays/overlay.hpp +++ b/include/overlays/overlay.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -28,15 +28,13 @@ #define _UNIVERSAL_UPDATER_OVERLAY_HPP #include "common.hpp" -#include "store.hpp" -#include "storeEntry.hpp" #include <3ds.h> namespace Overlays { - void SelectStore(std::unique_ptr &store, std::vector> &entries, std::unique_ptr &meta); - void SelectLanguage(const std::unique_ptr &store); + void SelectStore(); + void SelectLanguage(); void ShowCredits(); - std::string SelectDir(const std::string &oldDir, const std::string &msg, const std::unique_ptr &store); + std::string SelectDir(const std::string &oldDir, const std::string &msg); }; #endif \ No newline at end of file diff --git a/include/qr/qrcode.hpp b/include/qr/qrcode.hpp index 4ba578b..55426f6 100644 --- a/include/qr/qrcode.hpp +++ b/include/qr/qrcode.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/screens/mainScreen.hpp b/include/screens/mainScreen.hpp index 154bf1e..033615f 100644 --- a/include/screens/mainScreen.hpp +++ b/include/screens/mainScreen.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -37,11 +37,12 @@ 0: Entry Info. 1: Download List. - 2: Search + Favorites. - 3: Sorting. - 4: Settings / Credits(?). - 5: Screenshot Menu. - 6: Release Notes. + 2: Queue. + 3: Search + Favorites. + 4: Sorting. + 5: Settings / Credits(?). + 6: Screenshot Menu. + 7: Release Notes. */ class MainScreen : public Screen { @@ -50,21 +51,18 @@ public: void Draw(void) const override; void Logic(u32 hDown, u32 hHeld, touchPosition touch) override; private: - std::unique_ptr store = nullptr; - std::unique_ptr meta = nullptr; - std::vector> entries; std::vector dwnldList, dwnldSizes; bool initialized = false, fetchDown = false, showMarks = false, showSettings = false, - ascending = false, updateFilter = false, screenshotFetch = false, canDisplay = false; + ascending = false, updateFilter = false, screenshotFetch = false, canDisplay = false, isAND = true; int storeMode = 0, marks = 0, markIndex = 0, sPage = 0, lMode = 0, sSelection = 0, - lastMode = 0, smallDelay = 0, sPos = 0, screenshotIndex = 0, sSize = 0, zoom = 0, scrollIndex = 0; + lastMode = 0, smallDelay = 0, sPos = 0, screenshotIndex = 0, sSize = 0, zoom = 0, scrollIndex = 0, queueIndex = 0; SortType sorttype = SortType::LAST_UPDATED; /* Title, Author, Category, Console. */ - std::vector searchIncludes = { false, false, false, false }; + std::vector searchIncludes = { false, false, false, false }, installs = { }; std::string searchResult = "", screenshotName = ""; C2D_Image Screenshot = { nullptr, nullptr }; diff --git a/include/store/meta.hpp b/include/store/meta.hpp index d7bbec9..1a667a6 100644 --- a/include/store/meta.hpp +++ b/include/store/meta.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -29,6 +29,7 @@ #include "json.hpp" #include +#include enum favoriteMarks { STAR = 1 << 0, @@ -46,15 +47,58 @@ public: std::string GetUpdated(const std::string &unistoreName, const std::string &entry) const; int GetMarks(const std::string &unistoreName, const std::string &entry) const; bool UpdateAvailable(const std::string &unistoreName, const std::string &entry, const std::string &updated) const; + std::vector GetInstalled(const std::string &unistoreName, const std::string &entry) const; void SetUpdated(const std::string &unistoreName, const std::string &entry, const std::string &updated) { + if (this->metadataJson.is_discarded()) return; this->metadataJson[unistoreName][entry]["updated"] = updated; }; void SetMarks(const std::string &unistoreName, const std::string &entry, int marks) { + if (this->metadataJson.is_discarded()) return; this->metadataJson[unistoreName][entry]["marks"] = marks; }; + /* TODO: Handle this better. */ + void SetInstalled(const std::string &unistoreName, const std::string &entry, const std::string &name) { + if (this->metadataJson.is_discarded()) return; + + const std::vector installs = this->GetInstalled(unistoreName, entry); + bool write = true; + + if (!installs.empty()) { + write = !installs.empty(); + + for (int i = 0; i < (int)installs.size(); i++) { + if (installs[i] == name) { + write = false; + break; + } + } + } + + if (write) this->metadataJson[unistoreName][entry]["installed"] += name; + } + + /* Remove installed state from a download list entry. */ + void RemoveInstalled(const std::string &unistoreName, const std::string &entry, const std::string &name) { + if (this->metadataJson.is_discarded()) return; + + const std::vector installs = this->GetInstalled(unistoreName, entry); + int idx = -1; + + if (!installs.empty()) { + for (int i = 0; i < (int)installs.size(); i++) { + if (installs[i] == name) { + idx = i; + break; + } + } + } + + if (idx != -1) this->metadataJson[unistoreName][entry]["installed"].erase(idx); + } + void ImportMetadata(); void SaveCall(); private: diff --git a/include/store/store.hpp b/include/store/store.hpp index 0c95e55..06fa881 100644 --- a/include/store/store.hpp +++ b/include/store/store.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -44,7 +44,7 @@ public: std::string GetUniStoreTitle() const; std::string GetUniStoreAuthor() const; - /* Get Information of the UniStore Entries. */ + /* Get Information of the UniStore entries. */ std::string GetTitleEntry(int index) const; std::string GetAuthorEntry(int index) const; std::string GetDescriptionEntry(int index) const; diff --git a/include/store/storeEntry.hpp b/include/store/storeEntry.hpp index f04d70b..83d1832 100644 --- a/include/store/storeEntry.hpp +++ b/include/store/storeEntry.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/store/storeUtils.hpp b/include/store/storeUtils.hpp index f48dfa0..09bdc08 100644 --- a/include/store/storeUtils.hpp +++ b/include/store/storeUtils.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -27,7 +27,7 @@ #ifndef _UNIVERSAL_UPDATER_STORE_UTILS_HPP #define _UNIVERSAL_UPDATER_STORE_UTILS_HPP -#include "common.hpp" +#include "meta.hpp" #include "store.hpp" #include "storeEntry.hpp" #include @@ -39,33 +39,41 @@ enum class SortType : uint8_t { }; namespace StoreUtils { + extern std::unique_ptr meta; + extern std::unique_ptr store; + extern std::vector> entries; + /* Grid. */ - void DrawGrid(const std::unique_ptr &store, const std::vector> &entries); - void GridLogic(std::unique_ptr &store, std::vector> &entries, int ¤tMode, int &lastMode, bool &fetch, int &smallDelay); + void DrawGrid(); + void GridLogic(int ¤tMode, int &lastMode, bool &fetch, int &smallDelay); /* Top List. */ - void DrawList(const std::unique_ptr &store, const std::vector> &entries); - void ListLogic(std::unique_ptr &store, std::vector> &entries, int ¤tMode, int &lastMode, bool &fetch, int &smallDelay); + void DrawList(); + void ListLogic(int ¤tMode, int &lastMode, bool &fetch, int &smallDelay); /* Entry Info. */ - void DrawEntryInfo(const std::unique_ptr &store, const std::unique_ptr &entry); + void DrawEntryInfo(const std::unique_ptr &entry); void EntryHandle(bool &showMark, bool &fetch, bool &sFetch, int &mode, const std::unique_ptr &entry); /* Side Menu. */ void DrawSideMenu(int currentMenu); void SideMenuHandle(int ¤tMenu, bool &fetch, int &lastMenu); - /* Download Entries. */ - void DrawDownList(const std::unique_ptr &store, const std::vector &entries, bool fetch, const std::unique_ptr &entry, const std::vector &sizes); - void DownloadHandle(const std::unique_ptr &store, const std::unique_ptr &entry, const std::vector &entries, int ¤tMenu, std::unique_ptr &meta, const int &lastMode, int &smallDelay); + /* Download entries. */ + void DrawDownList(const std::vector &entries, bool fetch, const std::unique_ptr &entry, const std::vector &sizes, const std::vector &installs); + void DownloadHandle(const std::unique_ptr &entry, const std::vector &entries, int ¤tMenu, const int &lastMode, int &smallDelay, std::vector &installs); + + /* Queue System. */ + void DrawQueueMenu(const int queueIndex); + void QueueMenuHandle(int &queueIndex, int &storeMode); /* Search + Favorite Menu. */ - void DrawSearchMenu(const std::vector &searchIncludes, const std::string &searchResult, int marks, bool updateFilter); - void SearchHandle(std::unique_ptr &store, std::vector> &entries, std::vector &searchIncludes, std::unique_ptr &meta, std::string &searchResult, int &marks, bool &updateFilter, bool ascending, SortType sorttype); + void DrawSearchMenu(const std::vector &searchIncludes, const std::string &searchResult, int marks, bool updateFilter, bool isAND); + void SearchHandle(std::vector &searchIncludes, std::string &searchResult, int &marks, bool &updateFilter, bool ascending, SortType sorttype, bool &isAND); /* Mark Menu. */ void DisplayMarkBox(int marks); - void MarkHandle(std::unique_ptr &entry, const std::unique_ptr &store, bool &showMark, std::unique_ptr &meta); + void MarkHandle(std::unique_ptr &entry, bool &showMark); /* Credits. */ void DrawCredits(); @@ -76,14 +84,14 @@ namespace StoreUtils { /* Settings. */ void DrawSettings(int page, int selection, int sPos); - void SettingsHandle(int &page, bool &dspSettings, int &storeMode, int &selection, std::unique_ptr &store, std::vector> &entries, std::unique_ptr &meta, int &sPos); + void SettingsHandle(int &page, bool &dspSettings, int &storeMode, int &selection, int &sPos); /* Sorting. */ void DrawSorting(bool asc, SortType st); - void SortHandle(std::unique_ptr &store, std::vector> &entries, bool &asc, SortType &st); + void SortHandle(bool &asc, SortType &st); /* Release Notes. */ - void DrawReleaseNotes(const int &scrollIndex, const std::unique_ptr &entry, const std::unique_ptr &store); + void DrawReleaseNotes(const int &scrollIndex, const std::unique_ptr &entry); void ReleaseNotesLogic(int &scrollIndex, int &storeMode); bool compareTitleDescending(const std::unique_ptr &a, const std::unique_ptr &b); @@ -95,13 +103,18 @@ namespace StoreUtils { bool compareUpdateDescending(const std::unique_ptr &a, const std::unique_ptr &b); bool compareUpdateAscending(const std::unique_ptr &a, const std::unique_ptr &b); - void SortEntries(bool Ascending, SortType sorttype, std::vector> &entries); + void SortEntries(bool Ascending, SortType sorttype); - void search(std::vector> &entries, const std::string &query, bool title, bool author, bool category, bool console, int selectedMarks, bool updateAvl); + void search(const std::string &query, bool title, bool author, bool category, bool console, int selectedMarks, bool updateAvl, bool isAND); - void FilterUpdateAvailable(std::vector> &entries); + void FilterUpdateAvailable(); - void ResetAll(const std::unique_ptr &store, const std::unique_ptr &meta, std::vector> &entries); + void ResetAll(); + + void RefreshUpdateAVL(); + + void AddToQueue(int index, const std::string &entry, const std::string &entryName, const std::string &lUpdated); + void AddAllToQueue(); }; #endif \ No newline at end of file diff --git a/include/utils/animation.hpp b/include/utils/animation.hpp index 9e050d8..6f04151 100644 --- a/include/utils/animation.hpp +++ b/include/utils/animation.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -38,8 +38,17 @@ enum class ProgressBar { }; namespace Animation { + extern int DisplayY, DisplayDelay; + extern bool MoveUp, DoDelay; + void DrawProgressBar(u64 currentProgress, u64 totalProgress); void displayProgressBar(); + + void DrawQueue(int x, int y); + void QueueAnimHandle(); + + void QueueEntryDone(); + void HandleQueueEntryDone(); }; #endif \ No newline at end of file diff --git a/include/utils/argumentParser.hpp b/include/utils/argumentParser.hpp index eb2f9c3..fe7ac95 100644 --- a/include/utils/argumentParser.hpp +++ b/include/utils/argumentParser.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/utils/cia.hpp b/include/utils/cia.hpp index a4eece9..dcbaec0 100644 --- a/include/utils/cia.hpp +++ b/include/utils/cia.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/utils/config.hpp b/include/utils/config.hpp index 8b47bd6..c09ed28 100644 --- a/include/utils/config.hpp +++ b/include/utils/config.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -64,6 +64,9 @@ public: std::string archPath() const { return this->v_archivePath; }; void archPath(const std::string &v) { this->v_archivePath = v; if (!this->changesMade) this->changesMade = true; }; + std::string firmPath() const { return this->v_firmPath; }; + void firmPath(const std::string &v) { this->v_firmPath = v; if (!this->changesMade) this->changesMade = true; }; + /* Fetching old metadata. */ bool metadata() const { return this->v_metadata; }; void metadata(bool v) { this->v_metadata = v; if (!this->changesMade) this->changesMade = true; }; @@ -87,6 +90,14 @@ public: /* If displaying changelog. */ bool changelog() const { return this->v_changelog; }; void changelog(bool v) { this->v_changelog = v; if (!this->changesMade) this->changesMade = true; }; + + /* The active Theme. */ + int theme() const { return this->v_theme; }; + void theme(int v) { this->v_theme = v; if (!this->changesMade) this->changesMade = true; }; + + /* If showing prompt if action failed / succeeded. */ + bool prompt() const { return this->v_prompt; }; + void prompt(bool v) { this->v_prompt = v; if (!this->changesMade) this->changesMade = true; }; private: /* Mainly helper. */ bool getBool(const std::string &key); @@ -99,12 +110,14 @@ private: nlohmann::json json; bool changesMade = false; + int v_theme = 0; + std::string v_language = "en", v_lastStore = "universal-db.unistore", v_3dsxPath = "sdmc:/3ds", v_ndsPath = "sdmc:", v_archivePath = "sdmc:", - v_shortcutPath = "sdmc:/3ds/Universal-Updater/shortcuts"; + v_shortcutPath = "sdmc:/3ds/Universal-Updater/shortcuts", v_firmPath = "sdmc:/luma/payloads"; bool v_list = false, v_autoUpdate = true, v_metadata = true, v_updateCheck = true, - v_showBg = false, v_customFont = false, v_changelog = true; + v_showBg = false, v_customFont = false, v_changelog = true, v_prompt = true; }; #endif diff --git a/include/utils/download.hpp b/include/utils/download.hpp index 1fe590e..6fe5d44 100644 --- a/include/utils/download.hpp +++ b/include/utils/download.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/utils/extract.hpp b/include/utils/extract.hpp index 5437f4b..f462103 100644 --- a/include/utils/extract.hpp +++ b/include/utils/extract.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/utils/fileBrowse.hpp b/include/utils/fileBrowse.hpp index a716146..1d722a8 100644 --- a/include/utils/fileBrowse.hpp +++ b/include/utils/fileBrowse.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/utils/files.hpp b/include/utils/files.hpp index 259ce1d..90a8015 100644 --- a/include/utils/files.hpp +++ b/include/utils/files.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/utils/lang.hpp b/include/utils/lang.hpp index 2c5e87e..84432f1 100644 --- a/include/utils/lang.hpp +++ b/include/utils/lang.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/utils/queueSystem.hpp b/include/utils/queueSystem.hpp new file mode 100644 index 0000000..594ab37 --- /dev/null +++ b/include/utils/queueSystem.hpp @@ -0,0 +1,82 @@ +/* +* This file is part of Universal-Updater +* Copyright (C) 2019-2021 Universal-Team +* +* 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. +*/ + +#ifndef _UNIVERSAL_UPDATER_QUEUE_SYSTEM_HPP +#define _UNIVERSAL_UPDATER_QUEUE_SYSTEM_HPP + +#include "json.hpp" +#include +#include +#include + +/* Extend this, if more statuses are neccessary. */ +enum class QueueStatus { + None, + Copying, + Deleting, + Downloading, + Extracting, + Installing, + Moving, + Request, // For User needed Requests. + Failed, + Done +}; + +enum RequestType { + PROMPT_RET = -3, + NO_REQUEST = -1, + RMDIR_REQUEST = 1, // remove dir prompt request. + PROMPT_REQUEST = 2, // skip prompt request. + PROMPT_ERROR = 3 // Error message prompt. Unused right now. +}; + +class Queue { +public: + Queue(nlohmann::json object, const C2D_Image &img, const std::string &name, const std::string &uName, const std::string &eName, const std::string &lUpdated) : + obj(object), icn(img), name(name), unistoreName(uName), entryName(eName), lastUpdated(lUpdated) { }; + + QueueStatus status = QueueStatus::None; + nlohmann::json obj; + C2D_Image icn; + int total, current; + std::string name = "", unistoreName = "", entryName = "", lastUpdated = ""; +}; + +/* Of course also a namespace to that part, so we can do that in a Thread. */ +namespace QueueSystem { + extern int RequestNeeded, RequestAnswer; + extern std::string RequestMsg, EndMsg; + extern int LastElement; + extern bool Wait, Popup, CancelCallback; + + void QueueHandle(); // Handles the Queue. + void AddToQueue(nlohmann::json obj, const C2D_Image &icn, const std::string &name, const std::string &uName, const std::string &eName, const std::string &lUpdated); // Adds to Queue. + void ClearQueue(); // Clears the Queue. + void Resume(); +}; + +#endif \ No newline at end of file diff --git a/include/utils/screenshot.hpp b/include/utils/screenshot.hpp index cee108e..f30b191 100644 --- a/include/utils/screenshot.hpp +++ b/include/utils/screenshot.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/utils/scriptUtils.hpp b/include/utils/scriptUtils.hpp index 5f566d2..cbe7782 100644 --- a/include/utils/scriptUtils.hpp +++ b/include/utils/scriptUtils.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -44,15 +44,15 @@ enum ScriptState { namespace ScriptUtils { bool matchPattern(const std::string &pattern, const std::string &tested); - Result removeFile(const std::string &file, const std::string &message); - void bootTitle(const std::string &TitleID, bool isNAND, const std::string &message); + Result removeFile(const std::string &file, const std::string &message, bool isARG = false); + void bootTitle(const std::string &TitleID, bool isNAND, const std::string &message, bool isARG = false); Result prompt(const std::string &message); - Result copyFile(const std::string &source, const std::string &destination, const std::string &message); - Result renameFile(const std::string &oldName, const std::string &newName, const std::string &message); - Result downloadRelease(const std::string &repo, const std::string &file, const std::string &output, bool includePrereleases, const std::string &message); - Result downloadFile(const std::string &file, const std::string &output, const std::string &message); - void installFile(const std::string &file, bool updatingSelf, const std::string &message); - void extractFile(const std::string &file, const std::string &input, const std::string &output, const std::string &message); + Result copyFile(const std::string &source, const std::string &destination, const std::string &message, bool isARG = false); + Result renameFile(const std::string &oldName, const std::string &newName, const std::string &message, bool isARG = false); + Result downloadRelease(const std::string &repo, const std::string &file, const std::string &output, bool includePrereleases, const std::string &message, bool isARG = false); + Result downloadFile(const std::string &file, const std::string &output, const std::string &message, bool isARG = false); + void installFile(const std::string &file, bool updatingSelf, const std::string &message, bool isARG = false); + void extractFile(const std::string &file, const std::string &input, const std::string &output, const std::string &message, bool isARG = false); Result runFunctions(nlohmann::json storeJson, int selection, const std::string &entry); }; diff --git a/include/utils/sound.hpp b/include/utils/sound.hpp index c1f8796..4bbba3a 100644 --- a/include/utils/sound.hpp +++ b/include/utils/sound.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/include/utils/stringutils.hpp b/include/utils/stringutils.hpp index 2baea94..ebba606 100644 --- a/include/utils/stringutils.hpp +++ b/include/utils/stringutils.hpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -37,6 +37,7 @@ namespace StringUtils { std::string formatBytes(int bytes); std::string GetMarkString(int marks); std::vector GetMarks(int marks); + std::string format(const std::string &fmt_str, ...); }; #endif \ No newline at end of file diff --git a/romfs/lang/en/app.json b/romfs/lang/en/app.json index ea11251..eb3ab5f 100644 --- a/romfs/lang/en/app.json +++ b/romfs/lang/en/app.json @@ -1,4 +1,9 @@ { + "ACTION_CANCELED": "%s canceled!", + "ACTION_FAILED": "%s failed!", + "ACTION_REQUIRED": "Action required!", + "ACTION_SUCCEEDED": "%s succeeded!", + "ACTIVE_THEME": "Active Theme", "ASCENDING": "Ascending", "ARGUMENT_INVALID": "Argument invalid.\nPlease check the xml file for proper arguments.", "AUTHOR": "Author", @@ -13,6 +18,7 @@ "CATEGORY": "Category", "CHANGE_3DSX_PATH": "Change 3DSX path", "CHANGE_ARCHIVE_PATH": "Change archive path", + "CHANGE_FIRM_PATH": "Change firm path", "CHANGE_NDS_PATH": "Change NDS path", "CHANGE_SHORTCUT_PATH": "Change shortcut path", "CHECK_UNISTORE_UPDATES": "Checking for UniStore updates...", @@ -21,6 +27,7 @@ "CONNECT_WIFI": "Please Connect to WiFi.", "CONSOLE": "Console", "CONTRIBUTOR_TRANSLATORS": "- All Translators & Contributors", + "COPYING": "Copying... %s / %s (%.2f%%)", "COPY_ERROR": "Copy Error!", "CREATE_SHORTCUT": "Would you like to create a shortcut?", "CREDITS": "Credits", @@ -31,6 +38,7 @@ "DELETE_ERROR": "Delete Error!", "DELETE_PROMPT": "Are you sure you want to delete this Directory?", "DELETE_UNNEEDED_FILE": "Deleting unneeded file...", + "DELETING": "Deleting...", "DESCENDING": "Descending", "DIRECTION": "Direction", "DIRECTORY_SETTINGS": "Directory Settings", @@ -40,6 +48,8 @@ "DONE": "Done!", "DOWNLOAD_ERROR": "Download Error!", "DOWNLOAD_FAILED": "Download Failed!", + "DOWNLOAD_SPEED": "Speed: %lld KiB/s", + "DOWNLOADING": "Downloading... %s / %s (%.2f%%)", "DOWNLOADING_COMPATIBLE_FONT": "Downloading compatible font...", "DOWNLOADING_SPRITE_SHEET": "Downloading Spritesheet...", "DOWNLOADING_SPRITE_SHEET2": "Downloading Spritesheet %i of %i...", @@ -56,8 +66,11 @@ "ENTRIES": "Entries", "EXECUTE_ENTRY": "Would you like to execute this entry?", "EXIT_APP": "Exit Universal-Updater", + "EXTRACTING": "Extracting... %s / %s (%.2f%%)", + "FEATURE_SIDE_EFFECTS": "This Feature may have side effects while the Queue is running.\nAre you sure you want to continue?", "FETCHING_METADATA": "Fetching old metadata...", "FETCHING_RECOMMENDED_UNISTORES": "Fetching recommended UniStores...", + "FILES": "File: %d / %d", "FILE_EXTRACTED": "file extracted.", "FILE_SLASH": "Seems like a '/' is included, which is not supported.\nPlease change 'file' to filename only.", "FILES_EXTRACTED": "files extracted.", @@ -67,6 +80,7 @@ "GUI_SETTINGS": "GUI Settings", "GUI_SETTINGS_BTN": "GUI settings...", "INCLUDE_IN_RESULTS": "Include in results:", + "INSTALLING": "Installing... %s / %s (%.2f%%)", "INSTALL_UNIVERSAL_UPDATER": "Installing Universal-Updater...", "INVALID_UNISTORE": "Invalid UniStore", "KEY_CONTINUE": "Press any key to continue.", @@ -83,6 +97,16 @@ "NO_LICENSE": "No License", "NO_SCREENSHOTS_AVAILABLE": "No Screenshots available", "NOT_IMPLEMENTED": "Not Implemented Yet", + "OP_COPYING": "Copying", + "OP_DELETING": "Deleting", + "OP_DOWNLOADING": "Downloading", + "OP_EXTRACTING": "Extracting", + "OP_INSTALLING": "Installing", + "OP_MOVING": "Moving", + "OP_WAITING": "Waiting", + "QUEUE": "Queue", + "QUEUE_POSITION": "Queue position", + "QUEUE_PROGRESS": "Step: %d / %d", "RECOMMENDED_UNISTORES": "Recommended UniStores", "REVISION": "Revision", "SCREENSHOT": "Screenshot %d / %d", @@ -93,6 +117,7 @@ "SELECT_LANG": "Choose the language", "SELECT_UNISTORE": "Select UniStore", "SELECT_UNISTORE_2": "Select a UniStore", + "SELECTION_QUEUE": "Add Selection to Queue", "SETTINGS": "Settings", "SHEET_SLASH": "Seems like a '/' is included, which is not supported.\nPlease change 'sheet' to filename only.", "SHORTCUT_CREATED": "Shortcut created!", @@ -102,6 +127,7 @@ "START_SELECT": "Press START to select the current folder", "STORE_INFO": "Store Info", "SYNTAX_ERROR": "Syntax Error!", + "THEME_DEFAULT": "Default", "TITLE": "Title", "TOP_STYLE": "Top Style", "UNISTORE_BG": "Use UniStore BG", diff --git a/source/gui/gfx.cpp b/source/gui/gfx.cpp index bb42478..47695d6 100644 --- a/source/gui/gfx.cpp +++ b/source/gui/gfx.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -26,23 +26,49 @@ #include "common.hpp" #include "gfx.hpp" +#include "stringutils.hpp" +#include -/* - Draw the base top screen. -*/ +int GFX::SelectedTheme = 0; + +/* All available Themes here inside that vector. */ +std::vector GFX::Themes = { + /* Default Theme. */ + { + C2D_Color32(50, 73, 98, 255), // Bar. + C2D_Color32(38, 44, 77, 255), // BG. + C2D_Color32(25, 30, 53, 255), // Bar Outline. + WHITE, // Text. + C2D_Color32(50, 73, 98, 255), // Entry bar. + C2D_Color32(25, 30, 53, 255), // Entry Outline. + C2D_Color32(28, 33, 58, 255), // Box Inside. + C2D_Color32(108, 130, 155, 255), // Box Outside. + BLACK, // Box Unselected. + C2D_Color32(28, 33, 58, 255), // Progressbar Out. + C2D_Color32(77, 101, 128, 255), // Progressbar In. + C2D_Color32(51, 75, 102, 255), // Searchbar. + C2D_Color32(25, 30, 53, 255), // Searchbar Outline. + C2D_Color32(108, 130, 155, 255), // Sidebar Selected. + C2D_Color32(77, 101, 128, 255), // Sidebar Unselected. + C2D_Color32(77, 101, 128, 255), // Mark Selected. + C2D_Color32(28, 33, 58, 255), // Mark Unselected. + C2D_Color32(28, 33, 58, 255), // Downlist Preview (Top). + C2D_Color32(173, 204, 239, 255) // SideBar Icon Color. + } +}; + +/* Draw the base top screen. */ void GFX::DrawTop(void) { Gui::ScreenDraw(Top); - Gui::Draw_Rect(0, 0, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 26, 400, 214, BG_COLOR); - Gui::Draw_Rect(0, 25, 400, 1, BAR_OUTL_COLOR); + Gui::Draw_Rect(0, 0, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 26, 400, 214, GFX::Themes[GFX::SelectedTheme].BGColor); + Gui::Draw_Rect(0, 25, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); } -/* - Draw the base bottom screen. -*/ +/* Draw the base bottom screen. */ void GFX::DrawBottom() { Gui::ScreenDraw(Bottom); - Gui::Draw_Rect(0, 0, 320, 240, BG_COLOR); + Gui::Draw_Rect(0, 0, 320, 240, GFX::Themes[GFX::SelectedTheme].BGColor); } /* @@ -56,15 +82,15 @@ void GFX::DrawBottom() { uint32_t clr: (Optional) The color of the inside of the box. */ void GFX::DrawBox(float xPos, float yPos, float width, float height, bool selected, uint32_t clr) { - Gui::Draw_Rect(xPos, yPos, width, height, BOX_INSIDE_COLOR); // Draw middle BG. + Gui::Draw_Rect(xPos, yPos, width, height, GFX::Themes[GFX::SelectedTheme].BoxInside); // Draw middle BG. if (selected) { static constexpr int depth = 2; - Gui::Draw_Rect(xPos - depth, yPos - depth, width + depth * 2, depth, BOX_SELECTED_COLOR); // Top. - Gui::Draw_Rect(xPos - depth, yPos - depth, depth, height + depth * 2, BOX_SELECTED_COLOR); // Left. - Gui::Draw_Rect(xPos + width, yPos - depth, depth, height + depth * 2, BOX_SELECTED_COLOR); // Right. - Gui::Draw_Rect(xPos - depth, yPos + height, width + depth * 2, depth, BOX_SELECTED_COLOR); // Bottom. + Gui::Draw_Rect(xPos - depth, yPos - depth, width + depth * 2, depth, GFX::Themes[GFX::SelectedTheme].BoxSelected); // Top. + Gui::Draw_Rect(xPos - depth, yPos - depth, depth, height + depth * 2, GFX::Themes[GFX::SelectedTheme].BoxSelected); // Left. + Gui::Draw_Rect(xPos + width, yPos - depth, depth, height + depth * 2, GFX::Themes[GFX::SelectedTheme].BoxSelected); // Right. + Gui::Draw_Rect(xPos - depth, yPos + height, width + depth * 2, depth, GFX::Themes[GFX::SelectedTheme].BoxSelected); // Bottom. } } @@ -103,4 +129,71 @@ void GFX::DrawCheckbox(float xPos, float yPos, bool selected) { */ void GFX::DrawToggle(float xPos, float yPos, bool toggled) { GFX::DrawSprite((toggled ? sprites_toggle_on_idx : sprites_toggle_off_idx), xPos, yPos); +} + +void GFX::DrawTime() { + time_t unixTime = time(nullptr); + struct tm *timeStruct = gmtime((const time_t *)&unixTime); + const std::string str = StringUtils::format("%02i:%02i", timeStruct->tm_hour, timeStruct->tm_min); // :. + + Gui::DrawString(11, 5, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, str, 0, 0, font); +} + +static int blinkDelay = 40; +static bool blinkState = true, batteryLow = false; +void GFX::DrawBattery() { + u8 chargeState = false, level = 0; + PTMU_GetBatteryChargeState(&chargeState); // Get Charge state. + PTMU_GetBatteryLevel(&level); // Get Battery Level. + + if (chargeState) { + GFX::DrawSprite((level < 5 ? sprites_battery_charge_idx : sprites_battery_charge_full_idx), 366, 1); + if (batteryLow) batteryLow = false; // Cause we're charging. + + } else { + switch(level) { + case 0: // Blinky. + GFX::DrawSprite((blinkState ? sprites_battery_blink_idx : sprites_battery_0_idx), 366, 1); + if (!batteryLow) batteryLow = true; + break; + + case 1: // Red. + GFX::DrawSprite(sprites_battery_0_idx, 366, 1); + if (batteryLow) batteryLow = false; // Cause we're not low. + break; + + case 2: // One. + GFX::DrawSprite(sprites_battery_1_idx, 366, 1); + if (batteryLow) batteryLow = false; // Cause we're not low. + break; + + case 3: // Two. + GFX::DrawSprite(sprites_battery_2_idx, 366, 1); + if (batteryLow) batteryLow = false; // Cause we're not low. + break; + + case 4: // Three. + GFX::DrawSprite(sprites_battery_3_idx, 366, 1); + if (batteryLow) batteryLow = false; // Cause we're not low. + break; + + case 5: // Full. + GFX::DrawSprite(sprites_battery_4_idx, 366, 1); + if (batteryLow) batteryLow = false; // Cause we're not low. + break; + } + } +} + +void GFX::HandleBattery() { + if (batteryLow) { + if (blinkDelay > 0) { + blinkDelay--; + + if (blinkDelay == 0) { + blinkState = !blinkState; + blinkDelay = 40; + } + } + } } \ No newline at end of file diff --git a/source/gui/msg.cpp b/source/gui/msg.cpp index 9b1e5f3..b1f124f 100644 --- a/source/gui/msg.cpp +++ b/source/gui/msg.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -39,7 +39,7 @@ void Msg::DisplayMsg(const std::string &Text) { C2D_TargetClear(Bottom, TRANSPARENT); GFX::DrawTop(); - Gui::DrawStringCentered(0, (240 - Gui::GetStringHeight(0.6f, Text)) / 2, 0.6f, TEXT_COLOR, Text, 395, 0, font); + Gui::DrawStringCentered(0, (240 - Gui::GetStringHeight(0.6f, Text)) / 2, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Text, 395, 0, font); GFX::DrawBottom(); C3D_FrameEnd(0); } @@ -56,7 +56,7 @@ void Msg::DisplayWarnMsg(const std::string &Text) { C2D_TargetClear(Bottom, TRANSPARENT); GFX::DrawTop(); - Gui::DrawStringCentered(0, 1, 0.6f, TEXT_COLOR, Text, 390, 0, font); + Gui::DrawStringCentered(0, 1, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Text, 390, 0, font); GFX::DrawBottom(); C3D_FrameEnd(0); @@ -78,11 +78,11 @@ bool Msg::promptMsg(const std::string &promptMsg) { C2D_TargetClear(Bottom, TRANSPARENT); GFX::DrawTop(); - Gui::Draw_Rect(0, 215, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 214, 400, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, (240 - Gui::GetStringHeight(0.6f, promptMsg)) / 2, 0.6f, TEXT_COLOR, promptMsg, 395, 0, font); + Gui::Draw_Rect(0, 215, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 214, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, (240 - Gui::GetStringHeight(0.6f, promptMsg)) / 2, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, promptMsg, 395, 0, font); - Gui::DrawStringCentered(0, 218, 0.6f, TEXT_COLOR, Lang::get("CONFIRM_OR_CANCEL"), 390, 0, font); + Gui::DrawStringCentered(0, 218, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("CONFIRM_OR_CANCEL"), 390, 0, font); GFX::DrawBottom(); C3D_FrameEnd(0); @@ -110,10 +110,10 @@ void Msg::waitMsg(const std::string &msg) { C2D_TargetClear(Bottom, TRANSPARENT); GFX::DrawTop(); - Gui::DrawStringCentered(0, (240 - Gui::GetStringHeight(0.6f, msg)) / 2, 0.6f, TEXT_COLOR, msg, 395, 0, font); - Gui::Draw_Rect(0, 215, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 214, 400, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 218, 0.6f, TEXT_COLOR, Lang::get("KEY_CONTINUE"), 390, 0, font); + Gui::DrawStringCentered(0, (240 - Gui::GetStringHeight(0.6f, msg)) / 2, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, msg, 395, 0, font); + Gui::Draw_Rect(0, 215, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 214, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, 218, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("KEY_CONTINUE"), 390, 0, font); GFX::DrawBottom(); C3D_FrameEnd(0); diff --git a/source/init.cpp b/source/init.cpp index fc1354f..06bd471 100644 --- a/source/init.cpp +++ b/source/init.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -28,6 +28,7 @@ #include "download.hpp" #include "init.hpp" #include "mainScreen.hpp" +#include "queueSystem.hpp" #include "sound.hpp" #include @@ -120,6 +121,7 @@ Result Init::Initialize() { Gui::init(); cfguInit(); + ptmuInit(); amInit(); acInit(); @@ -136,6 +138,8 @@ Result Init::Initialize() { mkdir("sdmc:/3ds/Universal-Updater/shortcuts", 0777); config = std::make_unique(); + GFX::SelectedTheme = config->theme(); + if (GFX::SelectedTheme > (_THEME_AMOUNT - 1)) GFX::SelectedTheme = 0; // In case it is above the max themes. Lang::load(config->language()); Gui::loadSheet("romfs:/gfx/sprites.t3x", sprites); @@ -150,6 +154,7 @@ Result Init::Initialize() { Gui::setScreen(std::make_unique(), false, false); InitMusic(); + return 0; } @@ -173,11 +178,11 @@ Result Init::MainLoop() { C3D_FrameBegin(C3D_FRAME_SYNCDRAW); C2D_TargetClear(Top, C2D_Color32(0, 0, 0, 0)); C2D_TargetClear(Bottom, C2D_Color32(0, 0, 0, 0)); - Gui::DrawScreen(false); - if (!exiting) Gui::ScreenLogic(hDown, hHeld, touch, true, false); C3D_FrameEnd(0); + if (!exiting) Gui::ScreenLogic(hDown, hHeld, touch, true, false); + if (exiting) { if (hDown & KEY_START) fullExit = true; // Make it optionally faster. @@ -204,6 +209,7 @@ Result Init::Exit() { gfxExit(); cfguExit(); config->save(); + ptmuExit(); acExit(); amExit(); diff --git a/source/keyboard.cpp b/source/keyboard.cpp index 7eefc59..cadc573 100644 --- a/source/keyboard.cpp +++ b/source/keyboard.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/source/main.cpp b/source/main.cpp index 399013b..c292b16 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -33,9 +33,7 @@ #define ARG_AMOUNT 4 // In case for more args, change this. It must be ARG amount + 1, because of 3DSX Path. std::string _3dsxPath = ""; -/* - ARG Init. -*/ +/* ARG Init. */ static void InitForARG() { gfxInitDefault(); romfsInit(); @@ -51,14 +49,14 @@ static void InitForARG() { mkdir("sdmc:/3ds/Universal-Updater/shortcuts", 0777); config = std::make_unique(); + GFX::SelectedTheme = config->theme(); + if (GFX::SelectedTheme > (_THEME_AMOUNT - 1)) GFX::SelectedTheme = 0; // In case it is above the max themes. Lang::load(config->language()); Init::LoadFont(); osSetSpeedupEnable(true); // Enable speed-up for New 3DS users. } -/* - ARG Exit. -*/ +/* ARG Exit. */ static Result ExitForARG() { Gui::exit(); Init::UnloadFont(); diff --git a/source/store/downList.cpp b/source/menu/downList.cpp similarity index 52% rename from source/store/downList.cpp rename to source/menu/downList.cpp index fbe3fdd..90eb77c 100644 --- a/source/store/downList.cpp +++ b/source/menu/downList.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,7 +24,10 @@ * reasonable ways as different from the original version. */ +#include "animation.hpp" +#include "common.hpp" #include "keyboard.hpp" +#include "queueSystem.hpp" #include "scriptUtils.hpp" #include "storeUtils.hpp" #include "structs.hpp" @@ -35,15 +38,25 @@ extern std::string _3dsxPath; extern bool is3DSX; extern bool touching(touchPosition touch, Structs::ButtonPos button); static const std::vector downloadBoxes = { - { 54, 32, 262, 22 }, - { 54, 62, 262, 22 }, - { 54, 92, 262, 22 }, - { 54, 122, 262, 22 }, - { 54, 152, 262, 22 }, - { 54, 182, 262, 22 }, - { 54, 212, 262, 22 }, + { 46, 32, 241, 22 }, + { 46, 62, 241, 22 }, + { 46, 92, 241, 22 }, + { 46, 122, 241, 22 }, + { 46, 152, 241, 22 }, + { 46, 182, 241, 22 }, + { 46, 212, 241, 22 }, - { 50, 216, 24, 24 } + { 42, 216, 24, 24 } +}; + +static const std::vector installedPos = { + { 288, 32, 24, 24 }, + { 288, 62, 24, 24 }, + { 288, 92, 24, 24 }, + { 288, 122, 24, 24 }, + { 288, 152, 24, 24 }, + { 288, 182, 24, 24 }, + { 288, 212, 24, 24 }, }; /* @@ -87,51 +100,56 @@ static bool CreateShortcut(const std::string &entryName, int index, const std::s /* - Draw the Download Entries part. + Draw the Download entries part. - const std::unique_ptr &store: Const Reference to the Store class. const std::vector &entries: Const Reference to the download list as a vector of strings. bool fetch: if fetching or not. const std::unique_ptr &entry: Const Reference to the StoreEntry. const std::vector &sizes: Const Reference to the download sizes as a vector of strings. */ -void StoreUtils::DrawDownList(const std::unique_ptr &store, const std::vector &entries, bool fetch, const std::unique_ptr &entry, const std::vector &sizes) { +void StoreUtils::DrawDownList(const std::vector &entries, bool fetch, const std::unique_ptr &entry, const std::vector &sizes, const std::vector &installs) { /* For the Top Screen. */ - if (store && store->GetValid() && !fetch && entry) { + if (StoreUtils::store && StoreUtils::store->GetValid() && !fetch && entry) { if (entries.size() > 0) { - Gui::Draw_Rect(0, 174, 400, 66, BOX_INSIDE_COLOR); + Gui::Draw_Rect(0, 174, 400, 66, GFX::Themes[GFX::SelectedTheme].DownListPrev); const C2D_Image tempImg = entry->GetIcon(); const uint8_t offsetW = (48 - tempImg.subtex->width) / 2; // Center W. const uint8_t offsetH = (48 - tempImg.subtex->height) / 2; // Center H. - C2D_DrawImageAt(tempImg, 9 + offsetW, 174 + 9 + offsetH, 0.5); - Gui::DrawString(70, 174 + 15, 0.45f, TEXT_COLOR, entries[store->GetDownloadIndex()], 310, 0, font); + Gui::DrawString(70, 174 + 15, 0.45f, GFX::Themes[GFX::SelectedTheme].TextColor, entries[StoreUtils::store->GetDownloadIndex()], 310, 0, font); if (!sizes.empty()) { - if (sizes[store->GetDownloadIndex()] != "") { - Gui::DrawString(70, 174 + 30, 0.45f, TEXT_COLOR, Lang::get("SIZE") + ": " + sizes[store->GetDownloadIndex()], 310, 0, font); + if (sizes[StoreUtils::store->GetDownloadIndex()] != "") { + Gui::DrawString(70, 174 + 30, 0.45f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("SIZE") + ": " + sizes[StoreUtils::store->GetDownloadIndex()], 310, 0, font); } } } } - GFX::DrawBottom(); - Gui::Draw_Rect(48, 0, 272, 25, ENTRY_BAR_COLOR); - Gui::Draw_Rect(48, 25, 272, 1, ENTRY_BAR_OUTL_COLOR); - Gui::DrawStringCentered(25, 2, 0.6, TEXT_COLOR, Lang::get("AVAILABLE_DOWNLOADS"), 265, 0, font); + GFX::DrawTime(); + GFX::DrawBattery(); + Animation::QueueEntryDone(); - if (store && store->GetValid() && !fetch && entry) { + GFX::DrawBottom(); + Gui::Draw_Rect(40, 0, 280, 25, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(40, 25, 280, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); + Gui::DrawStringCentered(17, 2, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("AVAILABLE_DOWNLOADS"), 273, 0, font); + + if (StoreUtils::store && StoreUtils::store->GetValid() && !fetch && entry) { if (entries.size() > 0) { for (int i = 0; i < DOWNLOAD_ENTRIES && i < (int)entries.size(); i++) { - if (store->GetDownloadIndex() == i + store->GetDownloadSIndex()) GFX::DrawBox(downloadBoxes[i].x, downloadBoxes[i].y, downloadBoxes[i].w, downloadBoxes[i].h, false); - Gui::DrawStringCentered(54 - 160 + (262 / 2), downloadBoxes[i].y + 4, 0.45f, TEXT_COLOR, entries[(i + store->GetDownloadSIndex())], 260, 0, font); + if (StoreUtils::store->GetDownloadIndex() == i + StoreUtils::store->GetDownloadSIndex()) Gui::Draw_Rect(downloadBoxes[i].x, downloadBoxes[i].y, downloadBoxes[i].w, downloadBoxes[i].h, GFX::Themes[GFX::SelectedTheme].MarkSelected); + Gui::DrawStringCentered(46 - 160 + (241 / 2), downloadBoxes[i].y + 4, 0.45f, GFX::Themes[GFX::SelectedTheme].TextColor, entries[(i + StoreUtils::store->GetDownloadSIndex())], 235, 0, font); + + if (installs[(i + StoreUtils::store->GetDownloadSIndex())]) GFX::DrawSprite(sprites_installed_idx, installedPos[i].x, installedPos[i].y); } if (is3DSX) GFX::DrawSprite(sprites_shortcut_idx, downloadBoxes[6].x, downloadBoxes[6].y); + } else { // If no downloads available.. - Gui::DrawStringCentered(54 - 160 + (262 / 2), downloadBoxes[0].y + 4, 0.5f, TEXT_COLOR, Lang::get("NO_DOWNLOADS_AVAILABLE"), 255, 0, font); + Gui::DrawStringCentered(46 - 160 + (241 / 2), downloadBoxes[0].y + 4, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("NO_DOWNLOADS_AVAILABLE"), 235, 0, font); } } } @@ -144,26 +162,25 @@ void StoreUtils::DrawDownList(const std::unique_ptr &store, const std::ve - Execute an Entry of the download list. - Return back to EntryInfo through `B`. - const std::unique_ptr &store: Const Reference to the Store class, since we do not modify anything in it. const std::unique_ptr &entry: Const Reference to the current StoreEntry, since we do not modify anything in it. const std::vector &entries: Const Reference to the download list, since we do not modify anything in it. int ¤tMenu: Reference to the StoreMode / Menu, so we can switch back to EntryInfo with `B`. - std::unique_ptr &meta: Reference to the Meta, to apply the updates stuff. const int &lastMode: Const Reference to the last mode. int &smallDelay: Reference to the small delay. This helps to not directly press A. + std::vector &installs: Reference to the installed states. */ -void StoreUtils::DownloadHandle(const std::unique_ptr &store, const std::unique_ptr &entry, const std::vector &entries, int ¤tMenu, std::unique_ptr &meta, const int &lastMode, int &smallDelay) { - if (store && entry) { // Ensure, store & entry is not a nullptr. +void StoreUtils::DownloadHandle(const std::unique_ptr &entry, const std::vector &entries, int ¤tMenu, const int &lastMode, int &smallDelay, std::vector &installs) { + if (StoreUtils::store && entry) { // Ensure, store & entry is not a nullptr. if (smallDelay > 0) { smallDelay--; } if ((hDown & KEY_Y) || (hDown & KEY_START) || (hDown & KEY_TOUCH && touching(touch, downloadBoxes[6]))) { if (is3DSX) { // Only allow if 3DSX. - if (entries.size() <= 0) return; // Smaller than 0 -> No No. + if (StoreUtils::entries.size() <= 0) return; // Smaller than 0 -> No No. if (Msg::promptMsg(Lang::get("CREATE_SHORTCUT"))) { - if (CreateShortcut(entry->GetTitle(), store->GetDownloadIndex(), store->GetFileName(), entry->GetAuthor())) { + if (CreateShortcut(entry->GetTitle(), StoreUtils::store->GetDownloadIndex(), StoreUtils::store->GetFileName(), entry->GetAuthor())) { Msg::waitMsg(Lang::get("SHORTCUT_CREATED")); } } @@ -173,43 +190,62 @@ void StoreUtils::DownloadHandle(const std::unique_ptr &store, const std:: if (hRepeat & KEY_DOWN) { if (entries.size() <= 0) return; // Smaller *than* 0 -> Invalid. - if (store->GetDownloadIndex() < (int)entries.size() - 1) store->SetDownloadIndex(store->GetDownloadIndex() + 1); - else store->SetDownloadIndex(0); + if (StoreUtils::store->GetDownloadIndex() < (int)entries.size() - 1) StoreUtils::store->SetDownloadIndex(StoreUtils::store->GetDownloadIndex() + 1); + else StoreUtils::store->SetDownloadIndex(0); } if (hRepeat & KEY_UP) { if (entries.size() <= 0) return; // Smaller *than* 0 -> Invalid. - if (store->GetDownloadIndex() > 0) store->SetDownloadIndex(store->GetDownloadIndex() - 1); - else store->SetDownloadIndex(entries.size() - 1); + if (StoreUtils::store->GetDownloadIndex() > 0) StoreUtils::store->SetDownloadIndex(StoreUtils::store->GetDownloadIndex() - 1); + else StoreUtils::store->SetDownloadIndex(entries.size() - 1); } if (hRepeat & KEY_RIGHT) { if (entries.size() <= 0) return; // Smaller *than* 0 -> Invalid. - if (store->GetDownloadIndex() + DOWNLOAD_ENTRIES < (int)entries.size()-1) store->SetDownloadIndex(store->GetDownloadIndex() + DOWNLOAD_ENTRIES); - else store->SetDownloadIndex(entries.size()-1); + if (StoreUtils::store->GetDownloadIndex() + DOWNLOAD_ENTRIES < (int)entries.size()-1) StoreUtils::store->SetDownloadIndex(StoreUtils::store->GetDownloadIndex() + DOWNLOAD_ENTRIES); + else StoreUtils::store->SetDownloadIndex(entries.size()-1); } if (hRepeat & KEY_LEFT) { if (entries.size() <= 0) return; // Smaller *than* 0 -> Invalid. - if (store->GetDownloadIndex() - DOWNLOAD_ENTRIES > 0) store->SetDownloadIndex(store->GetDownloadIndex() - DOWNLOAD_ENTRIES); - else store->SetDownloadIndex(0); + if (StoreUtils::store->GetDownloadIndex() - DOWNLOAD_ENTRIES > 0) StoreUtils::store->SetDownloadIndex(StoreUtils::store->GetDownloadIndex() - DOWNLOAD_ENTRIES); + else StoreUtils::store->SetDownloadIndex(0); } if (smallDelay == 0 && hDown & KEY_TOUCH) { if (entries.size() <= 0) return; // Smaller *than* 0 -> Invalid. + bool didTouch = false; + for (int i = 0; i < DOWNLOAD_ENTRIES; i++) { if (touching(touch, downloadBoxes[i])) { - if (i + store->GetDownloadSIndex() < (int)entries.size()) { - if (Msg::promptMsg(Lang::get("EXECUTE_ENTRY") + "\n\n" + entries[i + store->GetDownloadSIndex()])) { - ScriptUtils::runFunctions(store->GetJson(), entry->GetEntryIndex(), entries[i + store->GetDownloadSIndex()]); - if (meta) meta->SetUpdated(store->GetUniStoreTitle(), entry->GetTitle(), entry->GetLastUpdated()); - entry->SetUpdateAvl(false); + if (i + StoreUtils::store->GetDownloadSIndex() < (int)entries.size()) { + if (Msg::promptMsg(Lang::get("EXECUTE_ENTRY") + "\n\n" + entries[i + StoreUtils::store->GetDownloadSIndex()])) { + StoreUtils::AddToQueue(entry->GetEntryIndex(), entries[i + StoreUtils::store->GetDownloadSIndex()], entry->GetTitle(), entry->GetLastUpdated()); } + + didTouch = true; + break; + } + } + } + + if (!didTouch) { + for (int i = 0; i < DOWNLOAD_ENTRIES; i++) { + if (touching(touch, installedPos[i])) { + if (i + StoreUtils::store->GetDownloadSIndex() < (int)entries.size()) { + if (installs[i + StoreUtils::store->GetDownloadSIndex()]) { + StoreUtils::meta->RemoveInstalled(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle(), entries[i + StoreUtils::store->GetDownloadSIndex()]); + installs[i + StoreUtils::store->GetDownloadSIndex()] = false; + } + } + + didTouch = true; + break; } } } @@ -218,17 +254,24 @@ void StoreUtils::DownloadHandle(const std::unique_ptr &store, const std:: if (smallDelay == 0 && hDown & KEY_A) { if (entries.size() <= 0) return; // Smaller *than* 0 -> Invalid. - if (Msg::promptMsg(Lang::get("EXECUTE_ENTRY") + "\n\n" + entries[store->GetDownloadIndex()])) { - ScriptUtils::runFunctions(store->GetJson(), entry->GetEntryIndex(), entries[store->GetDownloadIndex()]); - if (meta) meta->SetUpdated(store->GetUniStoreTitle(), entry->GetTitle(), entry->GetLastUpdated()); - entry->SetUpdateAvl(false); + if (Msg::promptMsg(Lang::get("EXECUTE_ENTRY") + "\n\n" + entries[StoreUtils::store->GetDownloadIndex()])) { + StoreUtils::AddToQueue(entry->GetEntryIndex(), entries[StoreUtils::store->GetDownloadIndex()], entry->GetTitle(), entry->GetLastUpdated()); + } + } + + if (hDown & KEY_X) { + if (entries.size() <= 0) return; // Smaller *than* 0 -> Invalid. + + if (installs[StoreUtils::store->GetDownloadIndex()]) { + StoreUtils::meta->RemoveInstalled(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle(), entries[StoreUtils::store->GetDownloadIndex()]); + installs[StoreUtils::store->GetDownloadIndex()] = false; } } if (hDown & KEY_B) currentMenu = lastMode; // Go back to EntryInfo. /* Scroll Handle. */ - if (store->GetDownloadIndex() < store->GetDownloadSIndex()) store->SetDownloadSIndex(store->GetDownloadIndex()); - else if (store->GetDownloadIndex() > store->GetDownloadSIndex() + DOWNLOAD_ENTRIES - 1) store->SetDownloadSIndex(store->GetDownloadIndex() - DOWNLOAD_ENTRIES + 1); + if (StoreUtils::store->GetDownloadIndex() < StoreUtils::store->GetDownloadSIndex()) StoreUtils::store->SetDownloadSIndex(StoreUtils::store->GetDownloadIndex()); + else if (StoreUtils::store->GetDownloadIndex() > StoreUtils::store->GetDownloadSIndex() + DOWNLOAD_ENTRIES - 1) StoreUtils::store->SetDownloadSIndex(StoreUtils::store->GetDownloadIndex() - DOWNLOAD_ENTRIES + 1); } } \ No newline at end of file diff --git a/source/store/entryInfo.cpp b/source/menu/entryInfo.cpp similarity index 54% rename from source/store/entryInfo.cpp rename to source/menu/entryInfo.cpp index c240c79..301301c 100644 --- a/source/store/entryInfo.cpp +++ b/source/menu/entryInfo.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,40 +24,41 @@ * reasonable ways as different from the original version. */ +#include "common.hpp" #include "storeUtils.hpp" #include "structs.hpp" extern bool touching(touchPosition touch, Structs::ButtonPos button); -static const Structs::ButtonPos btn = { 53, 215, 24, 24 }; -static const Structs::ButtonPos sshot = { 83, 215, 24, 24 }; -static const Structs::ButtonPos notes = { 113, 215, 24, 24 }; +static const Structs::ButtonPos btn = { 45, 215, 24, 24 }; +static const Structs::ButtonPos sshot = { 75, 215, 24, 24 }; +static const Structs::ButtonPos notes = { 105, 215, 24, 24 }; extern bool checkWifiStatus(); +extern bool QueueRuns; /* Draw the Entry Info part. - const std::unique_ptr &store: Const Reference to the Store class. const std::unique_ptr &entry: Const Reference to the current StoreEntry. */ -void StoreUtils::DrawEntryInfo(const std::unique_ptr &store, const std::unique_ptr &entry) { - if (store && entry) { // Ensure, store & entry is not a nullptr. - Gui::Draw_Rect(48, 0, 272, 36, ENTRY_BAR_COLOR); - Gui::Draw_Rect(48, 36, 272, 1, ENTRY_BAR_OUTL_COLOR); +void StoreUtils::DrawEntryInfo(const std::unique_ptr &entry) { + if (StoreUtils::store && entry) { // Ensure, store & entry is not a nullptr. + Gui::Draw_Rect(40, 0, 280, 36, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(40, 36, 280, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); - Gui::DrawStringCentered(25, 0, 0.6, TEXT_COLOR, entry->GetTitle(), 265, 0, font); - Gui::DrawStringCentered(25, 20, 0.4, TEXT_COLOR, entry->GetAuthor(), 265, 0, font); - Gui::DrawStringCentered(25, 50, 0.4, TEXT_COLOR, entry->GetDescription(), 240, 0, font, C2D_WordWrap); + Gui::DrawStringCentered(17, 0, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, entry->GetTitle(), 273, 0, font); + Gui::DrawStringCentered(17, 20, 0.4, GFX::Themes[GFX::SelectedTheme].TextColor, entry->GetAuthor(), 273, 0, font); + Gui::DrawStringCentered(17, 50, 0.4, GFX::Themes[GFX::SelectedTheme].TextColor, entry->GetDescription(), 248, 0, font, C2D_WordWrap); - Gui::DrawString(61, 130, 0.45, TEXT_COLOR, Lang::get("VERSION") + ": " + entry->GetVersion(), 240, 0, font); - Gui::DrawString(61, 145, 0.45, TEXT_COLOR, Lang::get("CATEGORY") + ": " + entry->GetCategory(), 240, 0, font); - Gui::DrawString(61, 160, 0.45, TEXT_COLOR, Lang::get("CONSOLE") + ": " + entry->GetConsole(), 240, 0, font); - Gui::DrawString(61, 175, 0.45, TEXT_COLOR, Lang::get("LAST_UPDATED") + ": " + entry->GetLastUpdated(), 240, 0, font); - Gui::DrawString(61, 190, 0.45, TEXT_COLOR, Lang::get("LICENSE") + ": " + entry->GetLicense(), 240, 0, font); + Gui::DrawString(53, 130, 0.45, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("VERSION") + ": " + entry->GetVersion(), 248, 0, font); + Gui::DrawString(53, 145, 0.45, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("CATEGORY") + ": " + entry->GetCategory(), 248, 0, font); + Gui::DrawString(53, 160, 0.45, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("CONSOLE") + ": " + entry->GetConsole(), 248, 0, font); + Gui::DrawString(53, 175, 0.45, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("LAST_UPDATED") + ": " + entry->GetLastUpdated(), 248, 0, font); + Gui::DrawString(53, 190, 0.45, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("LICENSE") + ": " + entry->GetLicense(), 248, 0, font); GFX::DrawBox(btn.x, btn.y, btn.w, btn.h, false); if (!entry->GetScreenshots().empty()) GFX::DrawSprite(sprites_screenshot_idx, sshot.x, sshot.y); if (entry->GetReleaseNotes() != "") GFX::DrawSprite(sprites_notes_idx, notes.x, notes.y); - Gui::DrawString(btn.x + 5, btn.y + 2, 0.6f, TEXT_COLOR, "★", 0, 0, font); + Gui::DrawString(btn.x + 5, btn.y + 2, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, "★", 0, 0, font); } } @@ -71,8 +72,8 @@ void StoreUtils::DrawEntryInfo(const std::unique_ptr &store, const std::u bool &showMark: Reference to showMark.. to show the mark menu. bool &fetch: Reference to fetch, so we know, if we need to fetch, when accessing download list. bool &sFetch: Reference to the screenshot fetch. - int &mode: Reference to the Store mode. - const std::unique_ptr &entry: The Store Entry. + int &mode: Reference to the store mode. + const std::unique_ptr &entry: The store Entry. */ void StoreUtils::EntryHandle(bool &showMark, bool &fetch, bool &sFetch, int &mode, const std::unique_ptr &entry) { if (entry) { @@ -81,14 +82,21 @@ void StoreUtils::EntryHandle(bool &showMark, bool &fetch, bool &sFetch, int &mod if ((hDown & KEY_Y) || (hDown & KEY_TOUCH && touching(touch, sshot))) { if (!entry->GetScreenshots().empty()) { if (checkWifiStatus()) { - sFetch = true; - mode = 5; + if (QueueRuns) { + if (!Msg::promptMsg(Lang::get("FEATURE_SIDE_EFFECTS"))) return; + sFetch = true; + mode = 6; + + } else { + sFetch = true; + mode = 6; + } } } } if ((hDown & KEY_X) || (hDown & KEY_TOUCH && touching(touch, notes))) { - if (entry->GetReleaseNotes() != "") mode = 6; + if (entry->GetReleaseNotes() != "") mode = 7; } } } \ No newline at end of file diff --git a/source/menu/grid.cpp b/source/menu/grid.cpp new file mode 100644 index 0000000..d54dc3c --- /dev/null +++ b/source/menu/grid.cpp @@ -0,0 +1,172 @@ +/* +* This file is part of Universal-Updater +* Copyright (C) 2019-2021 Universal-Team +* +* 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 "common.hpp" +#include "storeUtils.hpp" +#include "structs.hpp" + +static const std::vector GridBoxes = { + { 25, 45, 50, 50 }, + { 100, 45, 50, 50 }, + { 175, 45, 50, 50 }, + { 250, 45, 50, 50 }, + { 325, 45, 50, 50 }, + + { 25, 105, 50, 50 }, + { 100, 105, 50, 50 }, + { 175, 105, 50, 50 }, + { 250, 105, 50, 50 }, + { 325, 105, 50, 50 }, + + { 25, 165, 50, 50 }, + { 100, 165, 50, 50 }, + { 175, 165, 50, 50 }, + { 250, 165, 50, 50 }, + { 325, 165, 50, 50 } +}; + +/* Draw the Top Grid. */ +void StoreUtils::DrawGrid() { + if (StoreUtils::store) { // Ensure, store is not a nullptr. + + if (config->usebg() && StoreUtils::store->customBG()) { + C2D_DrawImageAt(StoreUtils::store->GetStoreImg(), 0, 26, 0.5f, nullptr); + + } else { + Gui::Draw_Rect(0, 26, 400, 214, GFX::Themes[GFX::SelectedTheme].BGColor); + } + + for (int i = 0, i2 = 0 + (StoreUtils::store->GetScreenIndx() * 5); i2 < 15 + (StoreUtils::store->GetScreenIndx() * 5) && i2 < (int)StoreUtils::entries.size(); i2++, i++) { + /* Boxes. */ + if (i == StoreUtils::store->GetBox()) GFX::DrawBox(GridBoxes[i].x, GridBoxes[i].y, 50, 50, true); + + /* Ensure, entries is larger than the index. */ + if ((int)StoreUtils::entries.size() > i2) { + if (StoreUtils::entries[i2]) { // Ensure, the Entry is not nullptr. + const C2D_Image tempImg = StoreUtils::entries[i2]->GetIcon(); + const uint8_t offsetW = (48 - tempImg.subtex->width) / 2; // Center W. + const uint8_t offsetH = (48 - tempImg.subtex->height) / 2; // Center H. + + C2D_DrawImageAt(tempImg, GridBoxes[i].x + 1 + offsetW, GridBoxes[i].y + 1 + offsetH, 0.5); + + /* Update Available mark. */ + if (StoreUtils::entries[i2]->GetUpdateAvl()) GFX::DrawSprite(sprites_update_app_idx, GridBoxes[i].x + 32, GridBoxes[i].y + 32); + } + } + } + } +} + + +/* + Top Grid Logic Handle. + Here you can.. + + - Scroll through the Grid with the D-Pad. + + const int ¤tMode: Reference to the current Mode. + int &lastMode: Reference to the last mode. + bool &fetch: Reference to fetch. + int &smallDelay: Reference to the small delay. +*/ +void StoreUtils::GridLogic(int ¤tMode, int &lastMode, bool &fetch, int &smallDelay) { + if (StoreUtils::store) { // Ensure, store is not a nullptr. + if (hRepeat & KEY_DOWN) { + if (StoreUtils::store->GetBox() > 9) { + if (StoreUtils::store->GetEntry() + 5 < (int)StoreUtils::entries.size() - 1) { + StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() + 5); + + if (StoreUtils::entries.size() > 15) StoreUtils::store->SetScreenIndx((StoreUtils::store->GetEntry() / 5) - 2); + + } else { + if (StoreUtils::store->GetEntry() < (int)StoreUtils::entries.size() - 1) { + StoreUtils::store->SetEntry(StoreUtils::entries.size() - 1); + StoreUtils::store->SetBox(10 + (StoreUtils::store->GetEntry() % 5)); + + if (StoreUtils::entries.size() > 15) StoreUtils::store->SetScreenIndx((StoreUtils::store->GetEntry() / 5) - 2); + } + } + + } else { + if (StoreUtils::store->GetEntry() + 5 < (int)StoreUtils::entries.size()) { + StoreUtils::store->SetBox(StoreUtils::store->GetBox() + 5); + StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() + 5); + } + } + } + + if (hRepeat & KEY_RIGHT) { + if (StoreUtils::store->GetEntry() < (int)StoreUtils::entries.size() - 1) { + if (StoreUtils::store->GetBox() < 14) { + StoreUtils::store->SetBox(StoreUtils::store->GetBox() + 1); + StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() + 1); + + } else { + StoreUtils::store->SetBox(10); + StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() + 1); + + StoreUtils::store->SetScreenIndx((StoreUtils::store->GetEntry() / 5) - 2); + } + } + } + + if (hRepeat & KEY_LEFT) { + if (StoreUtils::store->GetEntry() > 0) { + if (StoreUtils::store->GetBox() > 0) { + StoreUtils::store->SetBox(StoreUtils::store->GetBox() - 1); + StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() - 1); + + } else { + StoreUtils::store->SetBox(4); + StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() - 1); + + StoreUtils::store->SetScreenIndx((StoreUtils::store->GetEntry() / 5)); + } + } + } + + if (hRepeat & KEY_UP) { + if (StoreUtils::store->GetBox() < 5) { + if (StoreUtils::store->GetEntry() > 4) { + StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() - 5); + + StoreUtils::store->SetScreenIndx((StoreUtils::store->GetEntry() / 5)); + } + + } else { + StoreUtils::store->SetBox(StoreUtils::store->GetBox() - 5); + StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() - 5); + } + } + + if (hDown & KEY_A) { + fetch = true; + smallDelay = 5; + lastMode = currentMode; + currentMode = 1; + } + } +} \ No newline at end of file diff --git a/source/menu/list.cpp b/source/menu/list.cpp new file mode 100644 index 0000000..66fd7cf --- /dev/null +++ b/source/menu/list.cpp @@ -0,0 +1,119 @@ +/* +* This file is part of Universal-Updater +* Copyright (C) 2019-2021 Universal-Team +* +* 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 "common.hpp" +#include "storeUtils.hpp" +#include "structs.hpp" + +static const std::vector StoreBoxesList = { + { 20, 45, 360, 50 }, + { 20, 105, 360, 50 }, + { 20, 165, 360, 50 } +}; + +/* Draw the top List. */ +void StoreUtils::DrawList() { + if (StoreUtils::store) { // Ensure, store is not a nullptr. + + if (config->usebg() && StoreUtils::store->customBG()) { + C2D_DrawImageAt(StoreUtils::store->GetStoreImg(), 0, 26, 0.5f, nullptr); + + } else { + Gui::Draw_Rect(0, 26, 400, 214, GFX::Themes[GFX::SelectedTheme].BGColor); + } + + if (StoreUtils::entries.size() > 0) { + for (int i = 0; i < 3 && i < (int)StoreUtils::entries.size(); i++) { + + if (i + StoreUtils::store->GetScreenIndx() == StoreUtils::store->GetEntry()) { + GFX::DrawBox(StoreBoxesList[i].x, StoreBoxesList[i].y, StoreBoxesList[i].w, StoreBoxesList[i].h, false); + } + + /* Ensure, entries is larger than the index. */ + if ((int)StoreUtils::entries.size() > i + StoreUtils::store->GetScreenIndx()) { + if (StoreUtils::entries[i + StoreUtils::store->GetScreenIndx()]) { // Ensure, the Entry is not nullptr. + const C2D_Image tempImg = StoreUtils::entries[i + StoreUtils::store->GetScreenIndx()]->GetIcon(); + const uint8_t offsetW = (48 - tempImg.subtex->width) / 2; // Center W. + const uint8_t offsetH = (48 - tempImg.subtex->height) / 2; // Center H. + + C2D_DrawImageAt(tempImg, StoreBoxesList[i].x + 1 + offsetW, StoreBoxesList[i].y + 1 + offsetH, 0.5); + } + + if (StoreUtils::entries[i + StoreUtils::store->GetScreenIndx()]->GetUpdateAvl()) GFX::DrawSprite(sprites_update_app_idx, StoreBoxesList[i].x + 32, StoreBoxesList[i].y + 32); + Gui::DrawStringCentered(29, StoreBoxesList[i].y + 5, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, StoreUtils::entries[i + StoreUtils::store->GetScreenIndx()]->GetTitle(), 300, 0, font); + Gui::DrawStringCentered(29, StoreBoxesList[i].y + 24, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, StoreUtils::entries[i + StoreUtils::store->GetScreenIndx()]->GetAuthor(), 300, 0, font); + } + } + } + } +} + + +/* + Top List Logic Handle. + Here you can.. + + - Scroll through the Grid with the D-Pad Up / Down and skip 3 entries with Left / Right. + + int ¤tMode: Const Reference to the current Mode. + int &lastMode: Reference to the last mode. + bool &fetch: Reference to fetch. + int &smallDelay: Reference to the small delay. +*/ +void StoreUtils::ListLogic(int ¤tMode, int &lastMode, bool &fetch, int &smallDelay) { + if (StoreUtils::store) { // Ensure, store is not a nullptr. + if (hRepeat & KEY_DOWN) { + if (StoreUtils::store->GetEntry() < (int)StoreUtils::entries.size() - 1) StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() + 1); + else StoreUtils::store->SetEntry(0); + } + + if (hRepeat & KEY_RIGHT) { + if (StoreUtils::store->GetEntry() < (int)StoreUtils::entries.size() - 3) StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() + 3); + else StoreUtils::store->SetEntry(StoreUtils::entries.size() - 1); + } + + if (hRepeat & KEY_LEFT) { + if (StoreUtils::store->GetEntry() - 2 > 0) StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() - 3); + else StoreUtils::store->SetEntry(0); + } + + if (hRepeat & KEY_UP) { + if (StoreUtils::store->GetEntry() > 0) StoreUtils::store->SetEntry(StoreUtils::store->GetEntry() - 1); + else StoreUtils::store->SetEntry(StoreUtils::entries.size() - 1); + } + + if (hDown & KEY_A) { + fetch = true; + smallDelay = 5; + lastMode = currentMode; + currentMode = 1; + } + + /* Scroll Logic. */ + if (StoreUtils::store->GetEntry() < StoreUtils::store->GetScreenIndx()) StoreUtils::store->SetScreenIndx(StoreUtils::store->GetEntry()); + else if (StoreUtils::store->GetEntry() > StoreUtils::store->GetScreenIndx() + 3 - 1) StoreUtils::store->SetScreenIndx(StoreUtils::store->GetEntry() - 3 + 1); + } +} \ No newline at end of file diff --git a/source/store/markMenu.cpp b/source/menu/markMenu.cpp similarity index 51% rename from source/store/markMenu.cpp rename to source/menu/markMenu.cpp index d44c3ed..f40147f 100644 --- a/source/store/markMenu.cpp +++ b/source/menu/markMenu.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,6 +24,7 @@ * reasonable ways as different from the original version. */ +#include "common.hpp" #include "storeUtils.hpp" #include "structs.hpp" @@ -35,7 +36,7 @@ static const std::vector markBox = { { 196, 94, 52, 52 }, { 258, 94, 52, 52 }, - { 53, 215, 24, 24 } + { 45, 215, 24, 24 } }; /* @@ -47,28 +48,28 @@ void StoreUtils::DisplayMarkBox(int marks) { Gui::Draw_Rect(0, 0, 320, 240, DIM_COLOR); // Darken. Gui::Draw_Rect(markBox[0].x, markBox[0].y, markBox[0].w, markBox[0].h, (marks & favoriteMarks::STAR ? - SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); + GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); Gui::Draw_Rect(markBox[1].x, markBox[1].y, markBox[1].w, markBox[1].h, (marks & favoriteMarks::HEART ? - SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); + GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); Gui::Draw_Rect(markBox[2].x, markBox[2].y, markBox[2].w, markBox[2].h, (marks & favoriteMarks::DIAMOND ? - SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); + GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); Gui::Draw_Rect(markBox[3].x, markBox[3].y, markBox[3].w, markBox[3].h, (marks & favoriteMarks::CLUBS ? - SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); + GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); Gui::Draw_Rect(markBox[4].x, markBox[4].y, markBox[4].w, markBox[4].h, (marks & favoriteMarks::SPADE ? - SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); + GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); - Gui::DrawString(markBox[0].x + 15, markBox[0].y + 11, 0.9, TEXT_COLOR, "★", 0, 0, font); - Gui::DrawString(markBox[1].x + 15, markBox[1].y + 11, 0.9, TEXT_COLOR, "♥", 0, 0, font); - Gui::DrawString(markBox[2].x + 15, markBox[2].y + 11, 0.9, TEXT_COLOR, "♦", 0, 0, font); - Gui::DrawString(markBox[3].x + 15, markBox[3].y + 11, 0.9, TEXT_COLOR, "♣", 0, 0, font); - Gui::DrawString(markBox[4].x + 15, markBox[4].y + 11, 0.9, TEXT_COLOR, "♠", 0, 0, font); + Gui::DrawString(markBox[0].x + 15, markBox[0].y + 11, 0.9, GFX::Themes[GFX::SelectedTheme].TextColor, "★", 0, 0, font); + Gui::DrawString(markBox[1].x + 15, markBox[1].y + 11, 0.9, GFX::Themes[GFX::SelectedTheme].TextColor, "♥", 0, 0, font); + Gui::DrawString(markBox[2].x + 15, markBox[2].y + 11, 0.9, GFX::Themes[GFX::SelectedTheme].TextColor, "♦", 0, 0, font); + Gui::DrawString(markBox[3].x + 15, markBox[3].y + 11, 0.9, GFX::Themes[GFX::SelectedTheme].TextColor, "♣", 0, 0, font); + Gui::DrawString(markBox[4].x + 15, markBox[4].y + 11, 0.9, GFX::Themes[GFX::SelectedTheme].TextColor, "♠", 0, 0, font); GFX::DrawBox(markBox[5].x, markBox[5].y, markBox[5].w, markBox[5].h, false); - Gui::DrawString(markBox[5].x + 5, markBox[5].y + 2, 0.6f, TEXT_COLOR, "★", 0, 0, font); + Gui::DrawString(markBox[5].x + 5, markBox[5].y + 2, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, "★", 0, 0, font); } /* @@ -79,47 +80,45 @@ void StoreUtils::DisplayMarkBox(int marks) { - Return to EntryInfo with `B`. std::unique_ptr &entry: Reference to the current StoreEntry. - const std::unique_ptr &store: Const Reference to the Store, since we do not modify anything there. bool &showMark: Reference to showMark, so we know, if we should stay here or not. - std::unique_ptr &meta: Reference to the Meta class. */ -void StoreUtils::MarkHandle(std::unique_ptr &entry, const std::unique_ptr &store, bool &showMark, std::unique_ptr &meta) { +void StoreUtils::MarkHandle(std::unique_ptr &entry, bool &showMark) { hidScanInput(); touchPosition t; hidTouchRead(&t); - if (meta && entry && store) { + if (StoreUtils::meta && entry && StoreUtils::store) { if (hidKeysDown() & KEY_TOUCH) { /* Star. */ if (touching(t, markBox[0])) { - meta->SetMarks(store->GetUniStoreTitle(), entry->GetTitle(), - meta->GetMarks(store->GetUniStoreTitle(), entry->GetTitle()) ^ favoriteMarks::STAR); - entry->SetMark(meta->GetMarks(store->GetUniStoreTitle(), entry->GetTitle())); + StoreUtils::meta->SetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle(), + StoreUtils::meta->GetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle()) ^ favoriteMarks::STAR); + entry->SetMark(StoreUtils::meta->GetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle())); /* Heart. */ } else if (touching(t, markBox[1])) { - meta->SetMarks(store->GetUniStoreTitle(), entry->GetTitle(), - meta->GetMarks(store->GetUniStoreTitle(), entry->GetTitle()) ^ favoriteMarks::HEART); - entry->SetMark(meta->GetMarks(store->GetUniStoreTitle(), entry->GetTitle())); + StoreUtils::meta->SetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle(), + StoreUtils::meta->GetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle()) ^ favoriteMarks::HEART); + entry->SetMark(StoreUtils::meta->GetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle())); /* Diamond. */ } else if (touching(t, markBox[2])) { - meta->SetMarks(store->GetUniStoreTitle(), entry->GetTitle(), - meta->GetMarks(store->GetUniStoreTitle(), entry->GetTitle()) ^ favoriteMarks::DIAMOND); - entry->SetMark(meta->GetMarks(store->GetUniStoreTitle(), entry->GetTitle())); + StoreUtils::meta->SetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle(), + StoreUtils::meta->GetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle()) ^ favoriteMarks::DIAMOND); + entry->SetMark(StoreUtils::meta->GetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle())); /* Clubs. */ } else if (touching(t, markBox[3])) { - meta->SetMarks(store->GetUniStoreTitle(), entry->GetTitle(), - meta->GetMarks(store->GetUniStoreTitle(), entry->GetTitle()) ^ favoriteMarks::CLUBS); - entry->SetMark(meta->GetMarks(store->GetUniStoreTitle(), entry->GetTitle())); + StoreUtils::meta->SetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle(), + StoreUtils::meta->GetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle()) ^ favoriteMarks::CLUBS); + entry->SetMark(StoreUtils::meta->GetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle())); /* Spade. */ } else if (touching(t, markBox[4])) { - meta->SetMarks(store->GetUniStoreTitle(), entry->GetTitle(), - meta->GetMarks(store->GetUniStoreTitle(), entry->GetTitle()) ^ favoriteMarks::SPADE); + StoreUtils::meta->SetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle(), + StoreUtils::meta->GetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle()) ^ favoriteMarks::SPADE); - entry->SetMark(meta->GetMarks(store->GetUniStoreTitle(), entry->GetTitle())); + entry->SetMark(StoreUtils::meta->GetMarks(StoreUtils::store->GetUniStoreTitle(), entry->GetTitle())); } } } diff --git a/source/menu/queueMenu.cpp b/source/menu/queueMenu.cpp new file mode 100644 index 0000000..aed970b --- /dev/null +++ b/source/menu/queueMenu.cpp @@ -0,0 +1,311 @@ +/* +* This file is part of Universal-Updater +* Copyright (C) 2019-2021 Universal-Team +* +* 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 "common.hpp" +#include "queueSystem.hpp" +#include "scriptUtils.hpp" +#include "storeUtils.hpp" +#include "structs.hpp" +#include +#include // for std::min. + +extern u32 extractSize, writeOffset; +extern u32 installSize, installOffset; +extern u32 copyOffset, copySize; +extern int filesExtracted, extractFilesCount; + +extern curl_off_t downloadTotal; +extern curl_off_t downloadNow; +extern curl_off_t downloadSpeed; +extern CURL *CurlHandle; +bool ShowQueueProgress = true; // Queue Mode View. +int queueMenuIdx = 0; // Queue Menu Index. + +#define QUEUE_ENTRIES 2 // 2 entries per screen or so. +extern bool touching(touchPosition touch, Structs::ButtonPos button); + +static const std::vector QueueBoxes = { + { 47, 36, 266, 90 }, + { 47, 139, 266, 90 }, + { 292, 37, 20, 20 }, // Cancel current Queue. + { 292, 140, 20, 20 } // Remove next Queue. +}; + +extern std::deque> queueEntries; + +void DrawStatus(QueueStatus s) { + if (!ShowQueueProgress) { + if (!queueEntries.empty()) { + Gui::DrawString(QueueBoxes[0].x + 10, QueueBoxes[0].y + 5, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, queueEntries[0]->name, 230, 0, font); + + char prog[256]; + snprintf(prog, sizeof(prog), Lang::get("QUEUE_PROGRESS").c_str(), queueEntries[0]->current, queueEntries[0]->total); + Gui::DrawString(QueueBoxes[0].x + 241, QueueBoxes[0].y + 68, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, prog, 80, 0, font, C2D_AlignRight); + + Gui::Draw_Rect(QueueBoxes[0].x + 60, QueueBoxes[0].y + 30, 182, 30, GFX::Themes[GFX::SelectedTheme].ProgressbarOut); + Gui::Draw_Rect(QueueBoxes[0].x + 60 + 1, QueueBoxes[0].y + 30 + 1, (int)(((float)queueEntries[0]->current / (float)queueEntries[0]->total) * 180.0f), 28, GFX::Themes[GFX::SelectedTheme].ProgressbarIn); + + switch(s) { + case QueueStatus::Done: + case QueueStatus::Failed: + case QueueStatus::None: + break; + + case QueueStatus::Copying: + Gui::DrawString(QueueBoxes[0].x + 60, QueueBoxes[0].y + 68, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("OP_COPYING"), 120, 0, font); + break; + + case QueueStatus::Deleting: + Gui::DrawString(QueueBoxes[0].x + 60, QueueBoxes[0].y + 68, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("OP_DELETING"), 120, 0, font); + break; + + case QueueStatus::Downloading: + Gui::DrawString(QueueBoxes[0].x + 60, QueueBoxes[0].y + 68, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("OP_DOWNLOADING"), 120, 0, font); + break; + + case QueueStatus::Extracting: + Gui::DrawString(QueueBoxes[0].x + 60, QueueBoxes[0].y + 68, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("OP_EXTRACTING"), 120, 0, font); + break; + + case QueueStatus::Installing: + Gui::DrawString(QueueBoxes[0].x + 60, QueueBoxes[0].y + 68, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("OP_INSTALLING"), 120, 0, font); + break; + + case QueueStatus::Moving: + Gui::DrawString(QueueBoxes[0].x + 60, QueueBoxes[0].y + 68, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("OP_MOVING"), 120, 0, font); + break; + + case QueueStatus::Request: + Gui::DrawString(QueueBoxes[0].x + 60, QueueBoxes[0].y + 68, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("OP_WAITING"), 120, 0, font); + break; + } + } + + return; + } + + char str[256], str2[256]; + + /* Progress. */ + if (!queueEntries.empty()) { + char prog[256]; + snprintf(prog, sizeof(prog), Lang::get("QUEUE_PROGRESS").c_str(), queueEntries[0]->current, queueEntries[0]->total); + Gui::DrawString((QueueBoxes[0].x + 241), QueueBoxes[0].y + 68, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, prog, 80, 0, font, C2D_AlignRight); + } + + /* String Handle. */ + switch(s) { + case QueueStatus::Done: + case QueueStatus::Failed: + case QueueStatus::None: + case QueueStatus::Moving: + break; + + case QueueStatus::Copying: + snprintf(str, sizeof(str), Lang::get("COPYING").c_str(), + StringUtils::formatBytes(copyOffset).c_str(), + StringUtils::formatBytes(copySize).c_str(), + ((float)copyOffset/(float)copySize) * 100.0f); + break; + + case QueueStatus::Deleting: + snprintf(str, sizeof(str), Lang::get("DELETING").c_str()); + break; + + case QueueStatus::Downloading: + if (CurlHandle) curl_easy_getinfo(CurlHandle, CURLINFO_SPEED_DOWNLOAD_T, &downloadSpeed); + else downloadSpeed = 0; + + if (downloadTotal < 1.0f) downloadTotal = 1.0f; + if (downloadTotal < downloadNow) downloadTotal = downloadNow; + + snprintf(str, sizeof(str), Lang::get("DOWNLOADING").c_str(), + StringUtils::formatBytes(downloadNow).c_str(), + StringUtils::formatBytes(downloadTotal).c_str(), + ((float)downloadNow/(float)downloadTotal) * 100.0f); + + snprintf(str2, sizeof(str2), Lang::get("DOWNLOAD_SPEED").c_str(), + ((downloadSpeed / 1024))); + break; + + case QueueStatus::Extracting: + snprintf(str, sizeof(str), Lang::get("EXTRACTING").c_str(), + StringUtils::formatBytes(writeOffset).c_str(), + StringUtils::formatBytes(extractSize).c_str(), + ((float)writeOffset/(float)extractSize) * 100.0f); + + snprintf(str2, sizeof(str2), Lang::get("FILES").c_str(), + filesExtracted, extractFilesCount); + + break; + + case QueueStatus::Installing: + snprintf(str, sizeof(str), Lang::get("INSTALLING").c_str(), + StringUtils::formatBytes(installOffset).c_str(), + StringUtils::formatBytes(installSize).c_str(), + ((float)installOffset/(float)installSize) * 100.0f); + break; + + case QueueStatus::Request: + snprintf(str, sizeof(str), Lang::get("OP_WAITING").c_str()); + snprintf(str2, sizeof(str2), Lang::get("ACTION_REQUIRED").c_str()); + break; + } + + /* Draw Handle. */ + switch(s) { + case QueueStatus::Done: + case QueueStatus::Failed: + case QueueStatus::None: + break; + + case QueueStatus::Copying: + Gui::DrawString(QueueBoxes[0].x + 10, QueueBoxes[0].y + 5, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, str, 230, 0, font); + Gui::Draw_Rect(QueueBoxes[0].x + 60, QueueBoxes[0].y + 30, 182, 30, GFX::Themes[GFX::SelectedTheme].ProgressbarOut); + Gui::Draw_Rect(QueueBoxes[0].x + 60 + 1, QueueBoxes[0].y + 30 + 1, (int)(((float)copyOffset / (float)copySize) * 180.0f), 28, GFX::Themes[GFX::SelectedTheme].ProgressbarIn); + break; + + case QueueStatus::Deleting: + Gui::DrawString(QueueBoxes[0].x + 10, QueueBoxes[0].y + 5, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, str, 230, 0, font); + break; + + case QueueStatus::Downloading: + Gui::DrawString(QueueBoxes[0].x + 10, QueueBoxes[0].y + 5, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, str, 230, 0, font); + Gui::Draw_Rect(QueueBoxes[0].x + 60, QueueBoxes[0].y + 30, 182, 30, GFX::Themes[GFX::SelectedTheme].ProgressbarOut); + Gui::Draw_Rect(QueueBoxes[0].x + 60 + 1, QueueBoxes[0].y + 30 + 1, (int)(((float)downloadNow / (float)downloadTotal) * 180.0f), 28, GFX::Themes[GFX::SelectedTheme].ProgressbarIn); + Gui::DrawString(QueueBoxes[0].x + 60, QueueBoxes[0].y + 68, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, str2, 120, 0, font); + break; + + case QueueStatus::Extracting: + Gui::DrawString(QueueBoxes[0].x + 10, QueueBoxes[0].y + 5, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, str, 230, 0, font); + Gui::Draw_Rect(QueueBoxes[0].x + 60, QueueBoxes[0].y + 30, 182, 30, GFX::Themes[GFX::SelectedTheme].ProgressbarOut); + Gui::Draw_Rect(QueueBoxes[0].x + 60 + 1, QueueBoxes[0].y + 30 + 1, (int)(((float)writeOffset / (float)extractSize) * 180.0f), 28, GFX::Themes[GFX::SelectedTheme].ProgressbarIn); + Gui::DrawString(QueueBoxes[0].x + 60, QueueBoxes[0].y + 68, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, str2, 120, 0, font); + break; + + case QueueStatus::Installing: + Gui::DrawString(QueueBoxes[0].x + 10, QueueBoxes[0].y + 5, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, str, 230, 0, font); + Gui::Draw_Rect(QueueBoxes[0].x + 60, QueueBoxes[0].y + 30, 182, 30, GFX::Themes[GFX::SelectedTheme].ProgressbarOut); + Gui::Draw_Rect(QueueBoxes[0].x + 60 + 1, QueueBoxes[0].y + 30 + 1, (int)(((float)installOffset / (float)installSize) * 180.0f), 28, GFX::Themes[GFX::SelectedTheme].ProgressbarIn); + break; + + case QueueStatus::Moving: + Gui::DrawString(QueueBoxes[0].x + 10, QueueBoxes[0].y + 5, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("OP_MOVING"), 230, 0, font); + break; + + case QueueStatus::Request: + Gui::DrawString(QueueBoxes[0].x + 10, QueueBoxes[0].y + 5, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, str, 230, 0, font); + Gui::Draw_Rect(QueueBoxes[0].x + 60, QueueBoxes[0].y + 30, 182, 30, GFX::Themes[GFX::SelectedTheme].ProgressbarOut); + Gui::DrawStringCentered(QueueBoxes[0].x + 151 - 160, QueueBoxes[0].y + 32, 0.8f, GFX::Themes[GFX::SelectedTheme].TextColor, str2, 180, 0, font); + break; + } +} + +void StoreUtils::DrawQueueMenu(const int queueIndex) { + Gui::Draw_Rect(40, 0, 280, 25, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(40, 25, 280, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); + Gui::DrawStringCentered(17, 2, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("QUEUE"), 273, 0, font); + + if (!queueEntries.empty()) { + Gui::Draw_Rect(QueueBoxes[0].x, QueueBoxes[0].y, QueueBoxes[0].w, QueueBoxes[0].h, GFX::Themes[GFX::SelectedTheme].MarkSelected); + + const C2D_Image tempImg = queueEntries[0]->icn; + const uint8_t offsetW = (48 - tempImg.subtex->width) / 2; // Center W. + const uint8_t offsetH = (48 - tempImg.subtex->height) / 2; // Center H. + C2D_DrawImageAt(tempImg, QueueBoxes[0].x + 5 + offsetW, QueueBoxes[0].y + 21 + offsetH, 0.5f); + + DrawStatus(queueEntries[0]->status); + GFX::DrawSprite(sprites_cancel_idx, QueueBoxes[2].x, QueueBoxes[2].y); // Don't show until properly implemented. + + /* The next Queue Entries being displayed below. */ + if ((1 + queueMenuIdx) < (int)queueEntries.size()) { + Gui::Draw_Rect(QueueBoxes[1].x, QueueBoxes[1].y, QueueBoxes[1].w, QueueBoxes[1].h, GFX::Themes[GFX::SelectedTheme].MarkUnselected); + + const C2D_Image tempImg2 = queueEntries[1 + queueMenuIdx]->icn; + const uint8_t offsetW2 = (48 - tempImg2.subtex->width) / 2; // Center W. + const uint8_t offsetH2 = (48 - tempImg2.subtex->height) / 2; // Center H. + C2D_DrawImageAt(tempImg2, QueueBoxes[1].x + 5 + offsetW2, QueueBoxes[1].y + 21 + offsetH2, 0.5f); + + Gui::DrawString(QueueBoxes[1].x + 10, QueueBoxes[1].y + 5, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, queueEntries[1 + queueMenuIdx]->name, 230, 0, font); + + Gui::DrawString(QueueBoxes[1].x + 60, QueueBoxes[1].y + 30, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("QUEUE_POSITION") + ": " + std::to_string(queueMenuIdx + 1), 0, 0, font); + + /* Cancel. */ + GFX::DrawSprite(sprites_cancel_idx, QueueBoxes[3].x, QueueBoxes[3].y); + } + } +} + +void StoreUtils::QueueMenuHandle(int &queueIndex, int &storeMode) { + if (!queueEntries.empty()) { + if ((1 + queueMenuIdx) > (int)queueEntries.size() - 1) queueMenuIdx = std::max((int)(queueEntries.size() - 1) - 1, 0); // Ensure this really doesn't go below 0. + } + + if (hDown & KEY_TOUCH) { + /* Current Queue Cancel. */ + if (QueueSystem::RequestNeeded == NO_REQUEST && touching(touch, QueueBoxes[2])) { // Needs to be above the 0 one, otherwise the callback won't be accepted. + QueueSystem::CancelCallback = true; + + } else if (touching(touch, QueueBoxes[0])) { + if (QueueSystem::RequestNeeded != NO_REQUEST) { // -1 means no request. + switch(QueueSystem::RequestNeeded) { + case RMDIR_REQUEST: // Remove Directory message. + QueueSystem::RequestAnswer = Msg::promptMsg(QueueSystem::RequestMsg); + + QueueSystem::Wait = false; + QueueSystem::Resume(); + break; + + case PROMPT_REQUEST: // Skip prompt message. + QueueSystem::RequestAnswer = ScriptUtils::prompt(QueueSystem::RequestMsg); + + QueueSystem::Wait = false; + QueueSystem::Resume(); + break; + } + + } else { + ShowQueueProgress = !ShowQueueProgress; // In case no request expected, switch from progress to total progress mode etc. + } + + /* Remove from Queue. */ + } else if (touching(touch, QueueBoxes[3])) { // Remove Queue entries. + if (queueEntries.size() > 1) queueEntries.erase(queueEntries.begin() + 1 + queueMenuIdx); + } + } + + if (hDown & KEY_DOWN) { + if (!queueEntries.empty()) { + if ((1 + queueMenuIdx) < (int)queueEntries.size() - 1) queueMenuIdx++; + } + } + + if (hDown & KEY_UP) { + if (queueMenuIdx > 0) queueMenuIdx--; + } + + if (hDown & KEY_B) storeMode = 0; // Go to EntryInfo. +} \ No newline at end of file diff --git a/source/store/releaseNotes.cpp b/source/menu/releaseNotes.cpp similarity index 61% rename from source/store/releaseNotes.cpp rename to source/menu/releaseNotes.cpp index 9851651..fafc67b 100644 --- a/source/store/releaseNotes.cpp +++ b/source/menu/releaseNotes.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,24 +24,28 @@ * reasonable ways as different from the original version. */ +#include "animation.hpp" +#include "common.hpp" #include "download.hpp" #include "storeUtils.hpp" -void StoreUtils::DrawReleaseNotes(const int &scrollIndex, const std::unique_ptr &entry, const std::unique_ptr &store) { - if (entry && store) { +void StoreUtils::DrawReleaseNotes(const int &scrollIndex, const std::unique_ptr &entry) { + if (entry && StoreUtils::store) { Gui::ScreenDraw(Top); - Gui::Draw_Rect(0, 26, 400, 214, BG_COLOR); - Gui::DrawString(5, 25 - scrollIndex, 0.5f, TEXT_COLOR, entry->GetReleaseNotes(), 390, 0, font, C2D_WordWrap); - Gui::Draw_Rect(0, 0, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 25, 400, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 1, 0.7f, TEXT_COLOR, entry->GetTitle(), 390, 0, font); + Gui::Draw_Rect(0, 26, 400, 214, GFX::Themes[GFX::SelectedTheme].BGColor); + Gui::DrawString(5, 25 - scrollIndex, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, entry->GetReleaseNotes(), 390, 0, font, C2D_WordWrap); + Gui::Draw_Rect(0, 0, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 25, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, 1, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, entry->GetTitle(), 390, 0, font); } else { Gui::ScreenDraw(Top); - Gui::Draw_Rect(0, 0, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 25, 400, 1, BAR_OUTL_COLOR); - Gui::Draw_Rect(0, 26, 400, 214, BG_COLOR); + Gui::Draw_Rect(0, 0, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 25, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::Draw_Rect(0, 26, 400, 214, GFX::Themes[GFX::SelectedTheme].BGColor); } + + Animation::QueueEntryDone(); } /* @@ -85,18 +89,18 @@ void DisplayChangelog() { C2D_TargetClear(Bottom, C2D_Color32(0, 0, 0, 0)); Gui::ScreenDraw(Top); - Gui::Draw_Rect(0, 26, 400, 214, BG_COLOR); - Gui::DrawString(5, 25 - scrollIndex, 0.5f, TEXT_COLOR, notes, 390, 0, font, C2D_WordWrap); - Gui::Draw_Rect(0, 0, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 25, 400, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 1, 0.7f, TEXT_COLOR, "Universal-Updater", 390, 0, font); - Gui::Draw_Rect(0, 215, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 214, 400, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 217, 0.7f, TEXT_COLOR, C_V, 390, 0, font); + Gui::Draw_Rect(0, 26, 400, 214, GFX::Themes[GFX::SelectedTheme].BGColor); + Gui::DrawString(5, 25 - scrollIndex, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, notes, 390, 0, font, C2D_WordWrap); + Gui::Draw_Rect(0, 0, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 25, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, 1, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, "Universal-Updater", 390, 0, font); + Gui::Draw_Rect(0, 215, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 214, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, 217, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, C_V, 390, 0, font); GFX::DrawBottom(); - Gui::Draw_Rect(0, 0, 320, 25, BAR_COLOR); - Gui::Draw_Rect(0, 25, 320, 1, BAR_OUTL_COLOR); + Gui::Draw_Rect(0, 0, 320, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 25, 320, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); C3D_FrameEnd(0); hidScanInput(); diff --git a/source/store/screenshotMenu.cpp b/source/menu/screenshotMenu.cpp similarity index 81% rename from source/store/screenshotMenu.cpp rename to source/menu/screenshotMenu.cpp index 64e524e..553ec9e 100644 --- a/source/store/screenshotMenu.cpp +++ b/source/menu/screenshotMenu.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,6 +24,8 @@ * reasonable ways as different from the original version. */ +#include "animation.hpp" +#include "common.hpp" #include "storeUtils.hpp" #include "structs.hpp" @@ -43,15 +45,17 @@ extern bool checkWifiStatus(); */ void StoreUtils::DrawScreenshotMenu(const C2D_Image &img, const int sIndex, const bool sFetch, const int screenshotSize, const std::string &name, const int zoom, const bool canDisplay) { Gui::ScreenDraw(Top); - Gui::Draw_Rect(0, 0, 400, 240, BG_COLOR); + Gui::Draw_Rect(0, 0, 400, 240, GFX::Themes[GFX::SelectedTheme].BGColor); if (!canDisplay) { + Animation::QueueEntryDone(); + GFX::DrawBottom(); if (screenshotSize > 0) { // if texture is nullptr AND screenshot size is larger than 0. - Gui::DrawStringCentered(0, 2, 0.6f, WHITE, Lang::get("SCREENSHOT_COULD_NOT_LOAD"), 310); + Gui::DrawStringCentered(0, 2, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("SCREENSHOT_COULD_NOT_LOAD"), 310); } else { - Gui::DrawStringCentered(0, 2, 0.6f, WHITE, Lang::get("NO_SCREENSHOTS_AVAILABLE"), 310); + Gui::DrawStringCentered(0, 2, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("NO_SCREENSHOTS_AVAILABLE"), 310); } return; @@ -82,6 +86,7 @@ void StoreUtils::DrawScreenshotMenu(const C2D_Image &img, const int sIndex, cons delete top.subtex; } + Animation::QueueEntryDone(); GFX::DrawBottom(); /* Bottom. */ @@ -92,19 +97,20 @@ void StoreUtils::DrawScreenshotMenu(const C2D_Image &img, const int sIndex, cons delete bottom.subtex; } else { - Gui::Draw_Rect(0, 215, 320, 25, BAR_COLOR); - Gui::Draw_Rect(0, 214, 320, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 220, 0.5f, TEXT_COLOR, Lang::get("SCREENSHOT_INSTRUCTIONS"), 310, 0, font); + Gui::Draw_Rect(0, 215, 320, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 214, 320, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, 220, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("SCREENSHOT_INSTRUCTIONS"), 310, 0, font); char screenshots[0x100]; snprintf(screenshots, sizeof(screenshots), Lang::get("SCREENSHOT").c_str(), sIndex + 1, screenshotSize); - Gui::DrawStringCentered(0, 2, 0.6f, WHITE, screenshots, 310, 0, font); - Gui::DrawStringCentered(0, 40, 0.6f, WHITE, name, 310, 0, font); + Gui::DrawStringCentered(0, 2, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, screenshots, 310, 0, font); + Gui::DrawStringCentered(0, 40, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, name, 310, 0, font); } } else { + Animation::QueueEntryDone(); GFX::DrawBottom(); - Gui::DrawStringCentered(0, 2, 0.6f, WHITE, Lang::get("NO_SCREENSHOTS_AVAILABLE"), 310); + Gui::DrawStringCentered(0, 2, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("NO_SCREENSHOTS_AVAILABLE"), 310); } } } diff --git a/source/store/searchMenu.cpp b/source/menu/searchMenu.cpp similarity index 53% rename from source/store/searchMenu.cpp rename to source/menu/searchMenu.cpp index 2acb96f..da0cbd2 100644 --- a/source/store/searchMenu.cpp +++ b/source/menu/searchMenu.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,27 +24,35 @@ * reasonable ways as different from the original version. */ +#include "common.hpp" #include "keyboard.hpp" #include "storeUtils.hpp" #include "structs.hpp" extern bool touching(touchPosition touch, Structs::ButtonPos button); static const std::vector SearchMenu = { - { 55, 45, 258, 30 }, // Search bar. + { 51, 41, 262, 30 }, // Search bar. /* Includes. */ - { 85, 109, 50, 10 }, - { 85, 125, 50, 10 }, - { 167, 109, 50, 10 }, - { 167, 125, 50, 10 }, + { 85, 101, 50, 10 }, + { 85, 117, 50, 10 }, + { 167, 101, 50, 10 }, + { 167, 117, 50, 10 }, /* Filters. */ - { 82, 195, 30, 30 }, - { 117, 195, 30, 30 }, - { 152, 195, 30, 30 }, - { 187, 195, 30, 30 }, - { 222, 195, 30, 30 }, - { 257, 195, 30, 30 } + { 82, 159, 30, 30 }, + { 117, 159, 30, 30 }, + { 152, 159, 30, 30 }, + { 187, 159, 30, 30 }, + { 222, 159, 30, 30 }, + { 257, 159, 30, 30 }, + + /* Send to Queue. */ + { 91, 200, 185, 25 }, + + /* AND / OR. */ + { 222, 139, 30, 13 }, + { 257, 139, 30, 13 } }; /* @@ -54,57 +62,68 @@ static const std::vector SearchMenu = { const std::string &searchResult: Const Reference to the searchResult. int marks: The filter mark flags. bool updateFilter: The update filter. + isAND: isAND for the AND / OR mode. */ -void StoreUtils::DrawSearchMenu(const std::vector &searchIncludes, const std::string &searchResult, int marks, bool updateFilter) { - Gui::Draw_Rect(48, 0, 272, 25, ENTRY_BAR_COLOR); - Gui::Draw_Rect(48, 25, 272, 1, ENTRY_BAR_OUTL_COLOR); - Gui::DrawStringCentered(25, 2, 0.6, TEXT_COLOR, Lang::get("SEARCH_FILTERS"), 265, 0, font); +void StoreUtils::DrawSearchMenu(const std::vector &searchIncludes, const std::string &searchResult, int marks, bool updateFilter, bool isAND) { + Gui::Draw_Rect(40, 0, 280, 25, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(40, 25, 280, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); + Gui::DrawStringCentered(21, 2, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("SEARCH_FILTERS"), 269, 0, font); - Gui::Draw_Rect(54, 44, 260, SearchMenu[0].h + 2, SEARCH_BAR_OUTL_COLOR); - Gui::Draw_Rect(SearchMenu[0].x, SearchMenu[0].y, SearchMenu[0].w, SearchMenu[0].h, SEARCH_BAR_COLOR); + Gui::Draw_Rect(50, 40, 264, SearchMenu[0].h + 2, GFX::Themes[GFX::SelectedTheme].SearchbarOutline); + Gui::Draw_Rect(SearchMenu[0].x, SearchMenu[0].y, SearchMenu[0].w, SearchMenu[0].h, GFX::Themes[GFX::SelectedTheme].SearchBar); - Gui::DrawStringCentered(28, 50, 0.6, TEXT_COLOR, searchResult, 265, 0, font); + Gui::DrawStringCentered(24, 46, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, searchResult, 265, 0, font); /* Checkboxes. */ for (int i = 0; i < 4; i++) { GFX::DrawCheckbox(SearchMenu[i + 1].x, SearchMenu[i + 1].y, searchIncludes[i]); } - Gui::DrawString(84, 85, 0.5, TEXT_COLOR, Lang::get("INCLUDE_IN_RESULTS"), 265, 0, font); + Gui::DrawString(84, 81, 0.5, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("INCLUDE_IN_RESULTS"), 265, 0, font); - Gui::DrawString(SearchMenu[1].x + 18, SearchMenu[1].y + 1, 0.4, TEXT_COLOR, Lang::get("TITLE"), 90, 0, font); - Gui::DrawString(SearchMenu[2].x + 18, SearchMenu[2].y + 1, 0.4, TEXT_COLOR, Lang::get("AUTHOR"), 90, 0, font); + Gui::DrawString(SearchMenu[1].x + 18, SearchMenu[1].y + 1, 0.4, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("TITLE"), 90, 0, font); + Gui::DrawString(SearchMenu[2].x + 18, SearchMenu[2].y + 1, 0.4, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("AUTHOR"), 90, 0, font); - Gui::DrawString(SearchMenu[3].x + 18, SearchMenu[3].y + 1, 0.4, TEXT_COLOR, Lang::get("CATEGORY"), 90, 0, font); - Gui::DrawString(SearchMenu[4].x + 18, SearchMenu[4].y + 1, 0.4, TEXT_COLOR, Lang::get("CONSOLE"), 90, 0, font); + Gui::DrawString(SearchMenu[3].x + 18, SearchMenu[3].y + 1, 0.4, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("CATEGORY"), 90, 0, font); + Gui::DrawString(SearchMenu[4].x + 18, SearchMenu[4].y + 1, 0.4, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("CONSOLE"), 90, 0, font); /* Filters. */ - Gui::DrawString(84, 175, 0.5f, TEXT_COLOR, Lang::get("FILTER_TO"), 265, 0, font); + Gui::DrawString(84, SearchMenu[5].y - 20, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("FILTER_TO"), 265, 0, font); Gui::Draw_Rect(SearchMenu[5].x, SearchMenu[5].y, SearchMenu[5].w, SearchMenu[5].h, (marks & favoriteMarks::STAR ? - SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); + GFX::Themes[GFX::SelectedTheme].SideBarUnselected : GFX::Themes[GFX::SelectedTheme].BoxInside)); Gui::Draw_Rect(SearchMenu[6].x, SearchMenu[6].y, SearchMenu[6].w, SearchMenu[6].h, (marks & favoriteMarks::HEART ? - SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); + GFX::Themes[GFX::SelectedTheme].SideBarUnselected : GFX::Themes[GFX::SelectedTheme].BoxInside)); Gui::Draw_Rect(SearchMenu[7].x, SearchMenu[7].y, SearchMenu[7].w, SearchMenu[7].h, (marks & favoriteMarks::DIAMOND ? - SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); + GFX::Themes[GFX::SelectedTheme].SideBarUnselected : GFX::Themes[GFX::SelectedTheme].BoxInside)); Gui::Draw_Rect(SearchMenu[8].x, SearchMenu[8].y, SearchMenu[8].w, SearchMenu[8].h, (marks & favoriteMarks::CLUBS ? - SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); + GFX::Themes[GFX::SelectedTheme].SideBarUnselected : GFX::Themes[GFX::SelectedTheme].BoxInside)); Gui::Draw_Rect(SearchMenu[9].x, SearchMenu[9].y, SearchMenu[9].w, SearchMenu[9].h, (marks & favoriteMarks::SPADE ? - SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); + GFX::Themes[GFX::SelectedTheme].SideBarUnselected : GFX::Themes[GFX::SelectedTheme].BoxInside)); Gui::Draw_Rect(SearchMenu[10].x, SearchMenu[10].y, SearchMenu[10].w, SearchMenu[10].h, (updateFilter ? - SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); + GFX::Themes[GFX::SelectedTheme].SideBarUnselected : GFX::Themes[GFX::SelectedTheme].BoxInside)); - Gui::DrawString(SearchMenu[5].x + 9, SearchMenu[5].y + 7, 0.5f, TEXT_COLOR, "★", 0, 0, font); - Gui::DrawString(SearchMenu[6].x + 9, SearchMenu[6].y + 7, 0.5f, TEXT_COLOR, "♥", 0, 0, font); - Gui::DrawString(SearchMenu[7].x + 9, SearchMenu[7].y + 7, 0.5f, TEXT_COLOR, "♦", 0, 0, font); - Gui::DrawString(SearchMenu[8].x + 9, SearchMenu[8].y + 7, 0.5f, TEXT_COLOR, "♣", 0, 0, font); - Gui::DrawString(SearchMenu[9].x + 9, SearchMenu[9].y + 7, 0.5f, TEXT_COLOR, "♠", 0, 0, font); + Gui::DrawString(SearchMenu[5].x + 9, SearchMenu[5].y + 7, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "★", 0, 0, font); + Gui::DrawString(SearchMenu[6].x + 9, SearchMenu[6].y + 7, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "♥", 0, 0, font); + Gui::DrawString(SearchMenu[7].x + 9, SearchMenu[7].y + 7, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "♦", 0, 0, font); + Gui::DrawString(SearchMenu[8].x + 9, SearchMenu[8].y + 7, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "♣", 0, 0, font); + Gui::DrawString(SearchMenu[9].x + 9, SearchMenu[9].y + 7, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "♠", 0, 0, font); GFX::DrawSprite(sprites_update_filter_idx, SearchMenu[10].x + 8, SearchMenu[10].y + 8); + + Gui::Draw_Rect(SearchMenu[11].x, SearchMenu[11].y, SearchMenu[11].w, SearchMenu[11].h, GFX::Themes[GFX::SelectedTheme].MarkUnselected); + Gui::DrawStringCentered(23, SearchMenu[11].y + 6, 0.45f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("SELECTION_QUEUE"), 280, 0, font); + + /* AND / OR. */ + Gui::Draw_Rect(SearchMenu[12].x, SearchMenu[12].y, SearchMenu[12].w, SearchMenu[12].h, (isAND ? GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); + Gui::DrawString(SearchMenu[12].x + 4, SearchMenu[12].y, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, "AND", 0, 0, font); + + Gui::Draw_Rect(SearchMenu[13].x, SearchMenu[13].y, SearchMenu[13].w, SearchMenu[13].h, (!isAND ? GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); + Gui::DrawString(SearchMenu[13].x + 8, SearchMenu[13].y, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, "OR", 0, 0, font); } /* @@ -115,15 +134,13 @@ void StoreUtils::DrawSearchMenu(const std::vector &searchIncludes, const s - Search the UniStore. - Include stuff into the search. - std::unique_ptr &store: Reference to the Store class. - std::vector> &entries: Reference to the Store Entries. std::vector &searchIncludes: Reference to the searchIncludes. - std::unique_ptr &meta: Reference to the Meta class. std::string &searchResult: Reference to the searchResult. int &marks: Reference to the mark flags. bool &updateFilter: Reference to the update filter. + bool &isAND: Reference to isAND boolean for AND / OR mode. */ -void StoreUtils::SearchHandle(std::unique_ptr &store, std::vector> &entries, std::vector &searchIncludes, std::unique_ptr &meta, std::string &searchResult, int &marks, bool &updateFilter, bool ascending, SortType sorttype) { +void StoreUtils::SearchHandle(std::vector &searchIncludes, std::string &searchResult, int &marks, bool &updateFilter, bool ascending, SortType sorttype, bool &isAND) { /* Checkboxes. */ if (hDown & KEY_TOUCH) { bool didTouch = false; @@ -140,7 +157,7 @@ void StoreUtils::SearchHandle(std::unique_ptr &store, std::vector &store, std::vectorGetValid()) { // Only search, when valid. - StoreUtils::ResetAll(store, meta, entries); - StoreUtils::search(entries, searchResult, searchIncludes[0], searchIncludes[1], searchIncludes[2], searchIncludes[3], marks, updateFilter); - store->SetScreenIndx(0); - store->SetEntry(0); - store->SetBox(0); + if (StoreUtils::store && StoreUtils::store->GetValid()) { // Only search, when valid. + StoreUtils::ResetAll(); + StoreUtils::search(searchResult, searchIncludes[0], searchIncludes[1], searchIncludes[2], searchIncludes[3], marks, updateFilter, isAND); + StoreUtils::store->SetScreenIndx(0); + StoreUtils::store->SetEntry(0); + StoreUtils::store->SetBox(0); - StoreUtils::SortEntries(ascending, sorttype, entries); + StoreUtils::SortEntries(ascending, sorttype); } } } @@ -199,9 +227,9 @@ void StoreUtils::SearchHandle(std::unique_ptr &store, std::vectorGetValid()) { - StoreUtils::ResetAll(store, meta, entries); - StoreUtils::SortEntries(ascending, sorttype, entries); + if (StoreUtils::store && StoreUtils::store->GetValid()) { + StoreUtils::ResetAll(); + StoreUtils::SortEntries(ascending, sorttype); } } } \ No newline at end of file diff --git a/source/store/settings.cpp b/source/menu/settings.cpp similarity index 64% rename from source/store/settings.cpp rename to source/menu/settings.cpp index b6a8d5e..3e2d94b 100644 --- a/source/store/settings.cpp +++ b/source/menu/settings.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,45 +24,47 @@ * reasonable ways as different from the original version. */ +#include "common.hpp" #include "init.hpp" #include "overlay.hpp" #include "scriptUtils.hpp" #include "storeUtils.hpp" #include -extern bool exiting; +extern bool exiting, QueueRuns; extern bool touching(touchPosition touch, Structs::ButtonPos button); static const std::vector mainButtons = { - { 54, 32, 262, 22 }, - { 54, 62, 262, 22 }, - { 54, 92, 262, 22 }, - { 54, 122, 262, 22 }, - { 54, 152, 262, 22 }, - { 54, 182, 262, 22 }, - { 54, 212, 262, 22 } + { 45, 32, 271, 22 }, + { 45, 62, 271, 22 }, + { 45, 92, 271, 22 }, + { 45, 122, 271, 22 }, + { 45, 152, 271, 22 }, + { 45, 182, 271, 22 }, + { 45, 212, 271, 22 } }; static const std::vector langButtons = { - { 10, 34, 300, 22 }, - { 10, 64, 300, 22 }, - { 10, 94, 300, 22 }, - { 10, 124, 300, 22 }, - { 10, 154, 300, 22 }, - { 10, 184, 300, 22 }, + { 45, 32, 271, 22 }, + { 45, 62, 271, 22 }, + { 45, 92, 271, 22 }, + { 45, 122, 271, 22 }, + { 45, 152, 271, 22 }, + { 45, 182, 271, 22 }, - { 52, 220, 16, 16 } // Add Font. + { 45, 220, 16, 16 } // Add Font. }; static const std::vector toggleAbles = { - { 288, 64, 24, 24 }, - { 288, 140, 24, 24 } + { 288, 44, 24, 24 }, + { 288, 120, 24, 24 } }; -static const Structs::ButtonPos back = { 52, 0, 24, 24 }; // Back arrow for directory. +static const Structs::ButtonPos back = { 45, 0, 24, 24 }; // Back arrow for directory. +static const Structs::ButtonPos Themes = { 40, 220, 280, 24 }; // Themes. static const std::vector mainStrings = { "LANGUAGE", "SELECT_UNISTORE", "AUTO_UPDATE_SETTINGS_BTN", "GUI_SETTINGS_BTN", "DIRECTORY_SETTINGS_BTN", "CREDITS", "EXIT_APP" }; -static const std::vector dirStrings = { "CHANGE_3DSX_PATH", "CHANGE_NDS_PATH", "CHANGE_ARCHIVE_PATH", "CHANGE_SHORTCUT_PATH" }; +static const std::vector dirStrings = { "CHANGE_3DSX_PATH", "CHANGE_NDS_PATH", "CHANGE_ARCHIVE_PATH", "CHANGE_SHORTCUT_PATH", "CHANGE_FIRM_PATH" }; /* Note: Украïнська is spelled using a latin i with dieresis to work in the system font */ //static const std::vector languages = { "Bruh", "Dansk", "Deutsch", "English", "Español", "Français", "Italiano", "Lietuvių", "Magyar", "Polski", "Português", "Português (Brasil)", "Русский", "Украïнська", "日本語" }; @@ -70,19 +72,21 @@ static const std::vector dirStrings = { "CHANGE_3DSX_PATH", "CHANGE static const std::vector languages = { "Bruh", "Deutsch", "English", "Español", "Français", "Italiano", "Magyar", "Polski", "Português (Brasil)", "Русский", "Украïнська", "日本語" }; static const std::string langsTemp[] = { "br", "de", "en", "es", "fr", "it", "hu", "pl", "pt-BR", "ru", "uk", "jp"}; +static const std::vector ThemeNames = { "THEME_DEFAULT" }; + /* Main Settings. int selection: The Settings Selection. */ static void DrawSettingsMain(int selection) { - Gui::Draw_Rect(48, 0, 272, 25, ENTRY_BAR_COLOR); - Gui::Draw_Rect(48, 25, 272, 1, ENTRY_BAR_OUTL_COLOR); - Gui::DrawStringCentered(25, 2, 0.6, TEXT_COLOR, Lang::get("SETTINGS"), 265, 0, font); + Gui::Draw_Rect(40, 0, 280, 25, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(40, 25, 280, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); + Gui::DrawStringCentered(20, 2, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("SETTINGS"), 280, 0, font); for (int i = 0; i < 7; i++) { - if (i == selection) GFX::DrawBox(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, false); - Gui::DrawStringCentered(30, mainButtons[i].y + 4, 0.45f, TEXT_COLOR, Lang::get(mainStrings[i]), 255, 0, font); + if (i == selection) Gui::Draw_Rect(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, GFX::Themes[GFX::SelectedTheme].MarkSelected); + Gui::DrawStringCentered(20, mainButtons[i].y + 4, 0.45f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get(mainStrings[i]), 255, 0, font); } } @@ -93,15 +97,15 @@ static void DrawSettingsMain(int selection) { int sPos: The Screen Position. */ static void DrawLanguageSettings(int selection, int sPos) { - Gui::Draw_Rect(48, 0, 272, 25, ENTRY_BAR_COLOR); - Gui::Draw_Rect(48, 25, 272, 1, ENTRY_BAR_OUTL_COLOR); + Gui::Draw_Rect(40, 0, 280, 25, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(40, 25, 280, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); GFX::DrawSprite(sprites_arrow_idx, back.x, back.y); GFX::DrawSprite(sprites_add_font_idx, langButtons[6].x, langButtons[6].y); - Gui::DrawStringCentered(32, 2, 0.6, TEXT_COLOR, Lang::get("SELECT_LANG"), 240, 0, font); + Gui::DrawStringCentered(20, 2, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("SELECT_LANG"), 248, 0, font); for(int i = 0; i < 6 && i < (int)languages.size(); i++) { - if (sPos + i == selection) GFX::DrawBox(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, false); - Gui::DrawStringCentered(30, mainButtons[i].y + 4, 0.45f, TEXT_COLOR, languages[sPos + i], 280, 0, font); + if (sPos + i == selection) Gui::Draw_Rect(langButtons[i].x, langButtons[i].y, langButtons[i].w, langButtons[i].h, GFX::Themes[GFX::SelectedTheme].MarkSelected); + Gui::DrawStringCentered(20, langButtons[i].y + 4, 0.45f, GFX::Themes[GFX::SelectedTheme].TextColor, languages[sPos + i], 280, 0, font); } } @@ -111,14 +115,14 @@ static void DrawLanguageSettings(int selection, int sPos) { int selection: The Settings Selection. */ static void DrawSettingsDir(int selection) { - Gui::Draw_Rect(48, 0, 272, 25, ENTRY_BAR_COLOR); - Gui::Draw_Rect(48, 25, 272, 1, ENTRY_BAR_OUTL_COLOR); + Gui::Draw_Rect(40, 0, 280, 25, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(40, 25, 280, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); GFX::DrawSprite(sprites_arrow_idx, back.x, back.y); - Gui::DrawStringCentered(32, 2, 0.6, TEXT_COLOR, Lang::get("DIRECTORY_SETTINGS"), 240, 0, font); + Gui::DrawStringCentered(20, 2, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("DIRECTORY_SETTINGS"), 248, 0, font); - for (int i = 0; i < 4; i++) { - if (i == selection) GFX::DrawBox(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, false); - Gui::DrawStringCentered(30, mainButtons[i].y + 4, 0.45f, TEXT_COLOR, Lang::get(dirStrings[i]), 255, 0, font); + for (int i = 0; i < 5; i++) { + if (i == selection) Gui::Draw_Rect(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, GFX::Themes[GFX::SelectedTheme].MarkSelected); + Gui::DrawStringCentered(20, mainButtons[i].y + 4, 0.45f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get(dirStrings[i]), 255, 0, font); } } @@ -126,22 +130,22 @@ static void DrawSettingsDir(int selection) { Draw Auto-Update Settings page. */ static void DrawAutoUpdate(int selection) { - Gui::Draw_Rect(48, 0, 272, 25, ENTRY_BAR_COLOR); - Gui::Draw_Rect(48, 25, 272, 1, ENTRY_BAR_OUTL_COLOR); + Gui::Draw_Rect(40, 0, 280, 25, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(40, 25, 280, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); GFX::DrawSprite(sprites_arrow_idx, back.x, back.y); - Gui::DrawStringCentered(32, 2, 0.6, TEXT_COLOR, Lang::get("AUTO_UPDATE_SETTINGS"), 240, 0, font); + Gui::DrawStringCentered(20, 2, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("AUTO_UPDATE_SETTINGS"), 240, 0, font); /* Toggle Boxes. */ - Gui::Draw_Rect(48, 64, 273, 24, (selection == 0 ? SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); - Gui::DrawString(55, 68, 0.5f, TEXT_COLOR, Lang::get("AUTO_UPDATE_UNISTORE"), 210, 0, font); - GFX::DrawToggle(288, 64, config->autoupdate()); - Gui::DrawString(55, 95, 0.4f, TEXT_COLOR, Lang::get("AUTO_UPDATE_UNISTORE_DESC"), 265, 0, font, C2D_WordWrap); + Gui::Draw_Rect(40, 44, 280, 24, (selection == 0 ? GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); + Gui::DrawString(47, 48, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("AUTO_UPDATE_UNISTORE"), 210, 0, font); + GFX::DrawToggle(toggleAbles[0].x, toggleAbles[0].y, config->autoupdate()); + Gui::DrawString(47, 75, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("AUTO_UPDATE_UNISTORE_DESC"), 265, 0, font, C2D_WordWrap); - Gui::Draw_Rect(48, 140, 273, 24, (selection == 1 ? SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); - Gui::DrawString(55, 144, 0.5f, TEXT_COLOR, Lang::get("AUTO_UPDATE_UU"), 210, 0, font); - GFX::DrawToggle(288, 140, config->updatecheck()); - Gui::DrawString(55, 171, 0.4f, TEXT_COLOR, Lang::get("AUTO_UPDATE_UU_DESC"), 265, 0, font, C2D_WordWrap); + Gui::Draw_Rect(40, 120, 280, 24, (selection == 1 ? GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); + Gui::DrawString(47, 124, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("AUTO_UPDATE_UU"), 210, 0, font); + GFX::DrawToggle(toggleAbles[1].x, toggleAbles[1].y, config->updatecheck()); + Gui::DrawString(47, 151, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("AUTO_UPDATE_UU_DESC"), 265, 0, font, C2D_WordWrap); } /* @@ -150,21 +154,24 @@ static void DrawAutoUpdate(int selection) { int selection: The Settings Selection. */ static void DrawGUISettings(int selection) { - Gui::Draw_Rect(48, 0, 272, 25, ENTRY_BAR_COLOR); - Gui::Draw_Rect(48, 25, 272, 1, ENTRY_BAR_OUTL_COLOR); + Gui::Draw_Rect(40, 0, 280, 25, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(40, 25, 280, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); GFX::DrawSprite(sprites_arrow_idx, back.x, back.y); - Gui::DrawStringCentered(32, 2, 0.6, TEXT_COLOR, Lang::get("GUI_SETTINGS"), 240, 0, font); + Gui::DrawStringCentered(20, 2, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("GUI_SETTINGS"), 248, 0, font); - Gui::Draw_Rect(48, 64, 273, 24, (selection == 0 ? SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); - Gui::DrawString(55, 68, 0.5f, TEXT_COLOR, Lang::get("UNISTORE_BG"), 210, 0, font); - GFX::DrawToggle(288, 64, config->usebg()); - Gui::DrawString(55, 95, 0.4f, TEXT_COLOR, Lang::get("UNISTORE_BG_DESC"), 265, 0, font, C2D_WordWrap); + Gui::Draw_Rect(40, 44, 280, 24, (selection == 0 ? GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); + Gui::DrawString(47, 48, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("UNISTORE_BG"), 210, 0, font); + GFX::DrawToggle(toggleAbles[0].x, toggleAbles[0].y, config->usebg()); + Gui::DrawString(47, 75, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("UNISTORE_BG_DESC"), 265, 0, font, C2D_WordWrap); - Gui::Draw_Rect(48, 140, 273, 24, (selection == 1 ? SIDEBAR_UNSELECTED_COLOR : BOX_INSIDE_COLOR)); - Gui::DrawString(55, 144, 0.5f, TEXT_COLOR, Lang::get("CUSTOM_FONT"), 210, 0, font); - GFX::DrawToggle(288, 140, config->customfont()); - Gui::DrawString(55, 171, 0.4f, TEXT_COLOR, Lang::get("CUSTOM_FONT_DESC"), 265, 0, font, C2D_WordWrap); + Gui::Draw_Rect(40, 120, 280, 24, (selection == 1 ? GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); + Gui::DrawString(47, 124, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("CUSTOM_FONT"), 210, 0, font); + GFX::DrawToggle(toggleAbles[1].x, toggleAbles[1].y, config->customfont()); + Gui::DrawString(47, 151, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("CUSTOM_FONT_DESC"), 265, 0, font, C2D_WordWrap); + + Gui::Draw_Rect(40, 196, 280, 24, (selection == 2 ? GFX::Themes[GFX::SelectedTheme].MarkSelected : GFX::Themes[GFX::SelectedTheme].MarkUnselected)); + Gui::DrawString(47, 200, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("ACTIVE_THEME") + ": " + Lang::get(ThemeNames[GFX::SelectedTheme]), 210, 0, font); } @@ -180,13 +187,10 @@ static void DrawGUISettings(int selection) { int &page: Reference to the page. bool &dspSettings: Reference to the display Settings. - int &storeMode: Reference to the Store Mode. + int &storeMode: Reference to the store Mode. int &selection: Reference to the Selection. - std::unique_ptr &store: Reference to the Store class. - std::vector> &entries: Reference to the StoreEntries. - std::unique_ptr &meta: Reference to the Meta class. */ -static void SettingsHandleMain(int &page, bool &dspSettings, int &storeMode, int &selection, std::unique_ptr &store, std::vector> &entries, std::unique_ptr &meta) { +static void SettingsHandleMain(int &page, bool &dspSettings, int &storeMode, int &selection) { if (hDown & KEY_B) { selection = 0; storeMode = 0; @@ -218,7 +222,12 @@ static void SettingsHandleMain(int &page, bool &dspSettings, int &storeMode, int page = 4; } else if (touching(touch, mainButtons[1])) { - Overlays::SelectStore(store, entries, meta); + if (QueueRuns) { + if (Msg::promptMsg(Lang::get("FEATURE_SIDE_EFFECTS"))) Overlays::SelectStore(); + + } else { + Overlays::SelectStore(); + } } else if (touching(touch, mainButtons[2])) { selection = 0; @@ -236,7 +245,8 @@ static void SettingsHandleMain(int &page, bool &dspSettings, int &storeMode, int Overlays::ShowCredits(); } else if (touching(touch, mainButtons[6])) { - exiting = true; + if (QueueRuns) exiting = Msg::promptMsg(Lang::get("FEATURE_SIDE_EFFECTS")); + else exiting = true; } } @@ -248,7 +258,12 @@ static void SettingsHandleMain(int &page, bool &dspSettings, int &storeMode, int break; case 1: - Overlays::SelectStore(store, entries, meta); + if (QueueRuns) { + if (Msg::promptMsg(Lang::get("FEATURE_SIDE_EFFECTS"))) Overlays::SelectStore(); + + } else { + Overlays::SelectStore(); + } break; case 2: @@ -271,7 +286,8 @@ static void SettingsHandleMain(int &page, bool &dspSettings, int &storeMode, int break; case 6: - exiting = true; + if (QueueRuns) exiting = Msg::promptMsg(Lang::get("FEATURE_SIDE_EFFECTS")); + else exiting = true; break; } } @@ -287,14 +303,14 @@ static void SettingsHandleMain(int &page, bool &dspSettings, int &storeMode, int int &page: Reference to the page. int &selection: Reference to the Selection. */ -static void SettingsHandleDir(int &page, int &selection, const std::unique_ptr &store) { +static void SettingsHandleDir(int &page, int &selection) { if (hDown & KEY_B) { page = 0; selection = 4; } if (hRepeat & KEY_DOWN) { - if (selection < 3) selection++; + if (selection < 4) selection++; else selection = 0; } @@ -319,20 +335,24 @@ static void SettingsHandleDir(int &page, int &selection, const std::unique_ptr_3dsxPath(), Lang::get("SELECT_DIR"), store); + const std::string path = Overlays::SelectDir(config->_3dsxPath(), Lang::get("SELECT_DIR")); if (path != "") config->_3dsxPath(path); } else if (touching(touch, mainButtons[1])) { - const std::string path = Overlays::SelectDir(config->ndsPath(), Lang::get("SELECT_DIR"), store); + const std::string path = Overlays::SelectDir(config->ndsPath(), Lang::get("SELECT_DIR")); if (path != "") config->ndsPath(path); } else if (touching(touch, mainButtons[2])) { - const std::string path = Overlays::SelectDir(config->archPath(), Lang::get("SELECT_DIR"), store); + const std::string path = Overlays::SelectDir(config->archPath(), Lang::get("SELECT_DIR")); if (path != "") config->archPath(path); } else if (touching(touch, mainButtons[3])) { - const std::string path = Overlays::SelectDir(config->shortcut(), Lang::get("SELECT_DIR"), store); + const std::string path = Overlays::SelectDir(config->shortcut(), Lang::get("SELECT_DIR")); if (path != "") config->shortcut(path); + + } else if (touching(touch, mainButtons[4])) { + const std::string path = Overlays::SelectDir(config->firmPath(), Lang::get("SELECT_DIR")); + if (path != "") config->firmPath(path); } } @@ -341,24 +361,29 @@ static void SettingsHandleDir(int &page, int &selection, const std::unique_ptr_3dsxPath(), Lang::get("SELECT_DIR"), store); + path = Overlays::SelectDir(config->_3dsxPath(), Lang::get("SELECT_DIR")); if (path != "") config->_3dsxPath(path); break; case 1: - path = Overlays::SelectDir(config->ndsPath(), Lang::get("SELECT_DIR"), store); + path = Overlays::SelectDir(config->ndsPath(), Lang::get("SELECT_DIR")); if (path != "") config->ndsPath(path); break; case 2: - path = Overlays::SelectDir(config->archPath(), Lang::get("SELECT_DIR"), store); + path = Overlays::SelectDir(config->archPath(), Lang::get("SELECT_DIR")); if (path != "") config->archPath(path); break; case 3: - path = Overlays::SelectDir(config->shortcut(), Lang::get("SELECT_DIR"), store); + path = Overlays::SelectDir(config->shortcut(), Lang::get("SELECT_DIR")); if (path != "") config->shortcut(path); break; + + case 4: + path = Overlays::SelectDir(config->firmPath(), Lang::get("SELECT_DIR")); + if (path != "") config->firmPath(path); + break; } } } @@ -431,7 +456,7 @@ static void GUISettingsLogic(int &page, int &selection) { } if (hRepeat & KEY_DOWN) { - if (selection < 1) selection++; + if (selection < 2) selection++; } if (hRepeat & KEY_UP) { @@ -450,6 +475,12 @@ static void GUISettingsLogic(int &page, int &selection) { config->customfont(!config->customfont()); (config->customfont() ? Init::LoadFont() : Init::UnloadFont()); + + } else if (touching(touch, Themes)) { + if (GFX::SelectedTheme < (_THEME_AMOUNT - 1)) GFX::SelectedTheme++; + else GFX::SelectedTheme = 0; + + config->theme(GFX::SelectedTheme); } } @@ -464,6 +495,13 @@ static void GUISettingsLogic(int &page, int &selection) { (config->customfont() ? Init::LoadFont() : Init::UnloadFont()); break; + + case 2: + if (GFX::SelectedTheme < (_THEME_AMOUNT - 1)) GFX::SelectedTheme++; + else GFX::SelectedTheme = 0; + + config->theme(GFX::SelectedTheme); + break; } } } @@ -555,7 +593,7 @@ static void LanguageLogic(int &page, int &selection, int &sPos) { if (hDown & KEY_TOUCH) { if (touching(touch, langButtons[6])) { /* Download Font. */ - ScriptUtils::downloadFile("https://github.com/Universal-Team/extras/raw/master/files/universal-updater.bcfnt", "sdmc:/3ds/Universal-Updater/font.bcfnt", Lang::get("DOWNLOADING_COMPATIBLE_FONT")); + ScriptUtils::downloadFile("https://github.com/Universal-Team/extras/raw/master/files/universal-updater.bcfnt", "sdmc:/3ds/Universal-Updater/font.bcfnt", Lang::get("DOWNLOADING_COMPATIBLE_FONT"), true); config->customfont(true); Init::LoadFont(); } @@ -600,20 +638,18 @@ void StoreUtils::DrawSettings(int page, int selection, int sPos) { int &page: Reference to the page. bool &dspSettings: Reference to the display Settings. - int &storeMode: Reference to the Store Mode. + int &storeMode: Reference to the store Mode. int &selection: Reference to the Selection. - std::unique_ptr &store: Reference to the Store class. - std::vector> &entries: Reference to the StoreEntries. - std::unique_ptr &meta: Reference to the Meta class. + int &sPos: Reference to screen position. */ -void StoreUtils::SettingsHandle(int &page, bool &dspSettings, int &storeMode, int &selection, std::unique_ptr &store, std::vector> &entries, std::unique_ptr &meta, int &sPos) { +void StoreUtils::SettingsHandle(int &page, bool &dspSettings, int &storeMode, int &selection, int &sPos) { switch(page) { case 0: - SettingsHandleMain(page, dspSettings, storeMode, selection, store, entries, meta); + SettingsHandleMain(page, dspSettings, storeMode, selection); break; case 1: - SettingsHandleDir(page, selection, store); + SettingsHandleDir(page, selection); break; case 2: diff --git a/source/store/sideMenu.cpp b/source/menu/sideMenu.cpp similarity index 70% rename from source/store/sideMenu.cpp rename to source/menu/sideMenu.cpp index 72a0742..66c6f4a 100644 --- a/source/store/sideMenu.cpp +++ b/source/menu/sideMenu.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,40 +24,44 @@ * reasonable ways as different from the original version. */ +#include "animation.hpp" +#include "common.hpp" #include "storeUtils.hpp" #include "structs.hpp" extern bool touching(touchPosition touch, Structs::ButtonPos button); static const std::vector sidePos = { - { 0, 0, 48, 48 }, - { 0, 48, 48, 48 }, - { 0, 96, 48, 48 }, - { 0, 144, 48, 48 }, - { 0, 192, 48, 48 } + { 0, 0, 40, 40 }, + { 0, 40, 40, 40 }, + { 0, 80, 40, 40 }, + { 0, 120, 40, 40 }, + { 0, 160, 40, 40 }, + { 0, 200, 40, 40 } }; /* Draw the Side Menu part. - int currentMenu: The current Store Mode / Menu. + int currentMenu: The current store Mode / Menu. */ void StoreUtils::DrawSideMenu(int currentMenu) { - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 6; i++) { if (i == currentMenu) { - Gui::Draw_Rect(sidePos[i].x, sidePos[i].y, sidePos[i].w, sidePos[i].h, SIDEBAR_SELECTED_COLOR); + Gui::Draw_Rect(sidePos[i].x, sidePos[i].y, sidePos[i].w, sidePos[i].h, GFX::Themes[GFX::SelectedTheme].SideBarSelected); } else { - Gui::Draw_Rect(sidePos[i].x, sidePos[i].y, sidePos[i].w, sidePos[i].h, SIDEBAR_UNSELECTED_COLOR); + Gui::Draw_Rect(sidePos[i].x, sidePos[i].y, sidePos[i].w, sidePos[i].h, GFX::Themes[GFX::SelectedTheme].SideBarUnselected); } } - GFX::DrawSprite(sprites_info_idx, sidePos[0].x + 4, sidePos[0].y + 4); - GFX::DrawSprite(sprites_download_idx, sidePos[1].x + 4, sidePos[1].y + 4); - GFX::DrawSprite(sprites_search_idx, sidePos[2].x + 4, sidePos[2].y + 4); - GFX::DrawSprite(sprites_sort_idx, sidePos[3].x + 4, sidePos[3].y + 4); - GFX::DrawSprite(sprites_settings_idx, sidePos[4].x + 4, sidePos[4].y + 4); + GFX::DrawSprite(sprites_info_idx, sidePos[0].x, sidePos[0].y); + GFX::DrawSprite(sprites_download_idx, sidePos[1].x, sidePos[1].y); + Animation::DrawQueue(sidePos[2].x, sidePos[2].y); + GFX::DrawSprite(sprites_search_idx, sidePos[3].x, sidePos[3].y); + GFX::DrawSprite(sprites_sort_idx, sidePos[4].x, sidePos[4].y); + GFX::DrawSprite(sprites_settings_idx, sidePos[5].x, sidePos[5].y); - Gui::Draw_Rect(48, 0, 1, 240, BAR_OUTL_COLOR); + Gui::Draw_Rect(40, 0, 1, 240, GFX::Themes[GFX::SelectedTheme].BarOutline); } /* @@ -66,13 +70,15 @@ void StoreUtils::DrawSideMenu(int currentMenu) { - Switch between the Menus through the sidebar. - int ¤tMenu: Reference to the Store Mode / Menu. + int ¤tMenu: Reference to the store Mode / Menu. bool &fetch: Reference of the download fetch variable.. so we know, if we need to fetch the download entries. int &lastMenu: Reference to the last menu. */ void StoreUtils::SideMenuHandle(int ¤tMenu, bool &fetch, int &lastMenu) { + Animation::QueueAnimHandle(); + if (hDown & KEY_TOUCH) { - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 6; i++) { if (touching(touch, sidePos[i])) { lastMenu = currentMenu; if (i == 1) fetch = true; // Fetch download list, if 1. @@ -83,7 +89,7 @@ void StoreUtils::SideMenuHandle(int ¤tMenu, bool &fetch, int &lastMenu) { } if (hRepeat & KEY_R) { - if (currentMenu < 4) { + if (currentMenu < 5) { lastMenu = currentMenu; if (currentMenu + 1 == 1) fetch = true; // Fetch download list, if 1. currentMenu++; diff --git a/source/store/sortMenu.cpp b/source/menu/sortMenu.cpp similarity index 54% rename from source/store/sortMenu.cpp rename to source/menu/sortMenu.cpp index 9afd539..5a8db85 100644 --- a/source/store/sortMenu.cpp +++ b/source/menu/sortMenu.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,6 +24,7 @@ * reasonable ways as different from the original version. */ +#include "common.hpp" #include "keyboard.hpp" #include "storeUtils.hpp" #include "structs.hpp" @@ -31,19 +32,19 @@ extern bool touching(touchPosition touch, Structs::ButtonPos button); static const std::vector buttons = { - { 75, 60, 100, 16 }, - { 75, 80, 100, 16 }, - { 75, 100, 100, 16 }, + { 71, 60, 104, 16 }, + { 71, 80, 104, 16 }, + { 71, 100, 104, 16 }, - { 205, 60, 100, 16 }, - { 205, 80, 100, 16 }, + { 201, 60, 104, 16 }, + { 201, 80, 104, 16 }, - { 75, 170, 100, 16 }, - { 75, 190, 100, 16 } + { 71, 170, 104, 16 }, + { 71, 190, 104, 16 } }; static void DrawCheck(int pos, bool v) { - GFX::DrawSprite((v ? sprites_sort_checked_idx : sprites_sort_unchecked_idx), buttons[pos].x + 5, buttons[pos].y); + GFX::DrawSprite((v ? sprites_sort_checked_idx : sprites_sort_unchecked_idx), buttons[pos].x + 1, buttons[pos].y); } /* @@ -73,89 +74,87 @@ static const uint8_t GetType(SortType st) { SortType st: The SortType variable. */ void StoreUtils::DrawSorting(bool asc, SortType st) { - Gui::Draw_Rect(48, 0, 272, 25, ENTRY_BAR_COLOR); - Gui::Draw_Rect(48, 25, 272, 1, ENTRY_BAR_OUTL_COLOR); - Gui::DrawStringCentered(25, 2, 0.6, TEXT_COLOR, Lang::get("SORTING"), 265, 0, font); + Gui::Draw_Rect(40, 0, 280, 25, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(40, 25, 280, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); + Gui::DrawStringCentered(17, 2, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("SORTING"), 273, 0, font); /* Sort By. */ - Gui::DrawString(buttons[0].x + 5, buttons[0].y - 20, 0.6f, TEXT_COLOR, Lang::get("SORT_BY"), 90, 0, font); + Gui::DrawString(buttons[0].x + 1, buttons[0].y - 20, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("SORT_BY"), 90, 0, font); for (int i = 0; i < 3; i++) { DrawCheck(i, i == GetType(st)); } - Gui::DrawString(buttons[0].x + 25, buttons[0].y + 2, 0.4f, TEXT_COLOR, Lang::get("TITLE"), 80, 0, font); - Gui::DrawString(buttons[1].x + 25, buttons[1].y + 2, 0.4f, TEXT_COLOR, Lang::get("AUTHOR"), 80, 0, font); - Gui::DrawString(buttons[2].x + 25, buttons[2].y + 2, 0.4f, TEXT_COLOR, Lang::get("LAST_UPDATED"), 80, 0, font); + Gui::DrawString(buttons[0].x + 21, buttons[0].y + 2, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("TITLE"), 80, 0, font); + Gui::DrawString(buttons[1].x + 21, buttons[1].y + 2, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("AUTHOR"), 80, 0, font); + Gui::DrawString(buttons[2].x + 21, buttons[2].y + 2, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("LAST_UPDATED"), 80, 0, font); /* Direction. */ - Gui::DrawString(buttons[3].x + 5, buttons[3].y - 20, 0.6f, TEXT_COLOR, Lang::get("DIRECTION"), 80, 0, font); + Gui::DrawString(buttons[3].x + 1, buttons[3].y - 20, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("DIRECTION"), 80, 0, font); DrawCheck(3, asc); DrawCheck(4, !asc); - Gui::DrawString(buttons[3].x + 25, buttons[3].y + 2, 0.4f, TEXT_COLOR, Lang::get("ASCENDING"), 80, 0, font); - Gui::DrawString(buttons[4].x + 25, buttons[4].y + 2, 0.4f, TEXT_COLOR, Lang::get("DESCENDING"), 80, 0, font); + Gui::DrawString(buttons[3].x + 21, buttons[3].y + 2, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("ASCENDING"), 80, 0, font); + Gui::DrawString(buttons[4].x + 21, buttons[4].y + 2, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("DESCENDING"), 80, 0, font); /* Top Style. */ - Gui::DrawString(buttons[5].x + 5, buttons[5].y - 20, 0.6f, TEXT_COLOR, Lang::get("TOP_STYLE"), 90, 0, font); + Gui::DrawString(buttons[5].x + 1, buttons[5].y - 20, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("TOP_STYLE"), 90, 0, font); DrawCheck(5, config->list()); DrawCheck(6, !config->list()); - Gui::DrawString(buttons[5].x + 25, buttons[5].y + 2, 0.4f, TEXT_COLOR, Lang::get("LIST"), 90, 0, font); - Gui::DrawString(buttons[6].x + 25, buttons[6].y + 2, 0.4f, TEXT_COLOR, Lang::get("GRID"), 90, 0, font); + Gui::DrawString(buttons[5].x + 21, buttons[5].y + 2, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("LIST"), 90, 0, font); + Gui::DrawString(buttons[6].x + 21, buttons[6].y + 2, 0.4f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("GRID"), 90, 0, font); } /* Sort Handle. Here you can.. - - Sort your Entries to.. + - Sort your entries to.. - Title (Ascending / Descending). - Author (Ascending / Descending). - Last Updated Date (Ascending / Descending). - Change the Top Style. - std::unique_ptr &store: Reference to the Store class. - std::vector> &entries: Reference to the StoreEntries. bool &asc: Reference to the Ascending variable. SortType &st: Reference to the SortType. */ -void StoreUtils::SortHandle(std::unique_ptr &store, std::vector> &entries, bool &asc, SortType &st) { - if (store && store->GetValid() && entries.size() > 0) { // Ensure, this is valid and more than 0 entries exist. +void StoreUtils::SortHandle(bool &asc, SortType &st) { + if (StoreUtils::store && StoreUtils::store->GetValid() && StoreUtils::entries.size() > 0) { // Ensure, this is valid and more than 0 StoreUtils::entries exist. if (hDown & KEY_TOUCH) { /* SortType Part. */ if (touching(touch, buttons[0])) { st = SortType::TITLE; - StoreUtils::SortEntries(asc, st, entries); + StoreUtils::SortEntries(asc, st); } else if (touching(touch, buttons[1])) { st = SortType::AUTHOR; - StoreUtils::SortEntries(asc, st, entries); + StoreUtils::SortEntries(asc, st); } else if (touching(touch, buttons[2])) { st = SortType::LAST_UPDATED; - StoreUtils::SortEntries(asc, st, entries); + StoreUtils::SortEntries(asc, st); /* Ascending | Descending Part. */ } else if (touching(touch, buttons[3])) { asc = true; - StoreUtils::SortEntries(asc, st, entries); + StoreUtils::SortEntries(asc, st); } else if (touching(touch, buttons[4])) { asc = false; - StoreUtils::SortEntries(asc, st, entries); + StoreUtils::SortEntries(asc, st); } else if (touching(touch, buttons[5])) { if (config->list()) return; config->list(true); - store->SetEntry(0); - store->SetScreenIndx(0); - store->SetBox(0); + StoreUtils::store->SetEntry(0); + StoreUtils::store->SetScreenIndx(0); + StoreUtils::store->SetBox(0); } else if (touching(touch, buttons[6])) { if (!config->list()) return; config->list(false); - store->SetEntry(0); - store->SetScreenIndx(0); - store->SetBox(0); + StoreUtils::store->SetEntry(0); + StoreUtils::store->SetScreenIndx(0); + StoreUtils::store->SetBox(0); } } } diff --git a/source/overlays/credits.cpp b/source/overlays/credits.cpp index c0eba36..d755b25 100644 --- a/source/overlays/credits.cpp +++ b/source/overlays/credits.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,11 +24,12 @@ * reasonable ways as different from the original version. */ +#include "animation.hpp" +#include "common.hpp" #include "overlay.hpp" +#include "version.hpp" -/* - Show the Credits. -*/ +/* Show the Credits. */ void Overlays::ShowCredits() { bool doOut = false; @@ -40,27 +41,29 @@ void Overlays::ShowCredits() { GFX::DrawTop(); GFX::DrawSprite(sprites_universal_updater_idx, 220, 26); - Gui::DrawStringCentered(0, 1, 0.7f, TEXT_COLOR, "Universal-Updater - " + Lang::get("CREDITS"), 395, 0, font); + Gui::DrawStringCentered(0, 1, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, "Universal-Updater - " + Lang::get("CREDITS"), 395, 0, font); - Gui::DrawString(10, 30, 0.5f, TEXT_COLOR, "- Universal-Team", 0, 0, font); - Gui::DrawString(10, 50, 0.5f, TEXT_COLOR, "- devkitPro", 0, 0, font); - Gui::DrawString(10, 70, 0.5f, TEXT_COLOR, "- dlbeer", 0, 0, font); - Gui::DrawString(10, 90, 0.5f, TEXT_COLOR, "- FlagBrew", 0, 0, font); - Gui::DrawString(10, 110, 0.5f, TEXT_COLOR, "- https://icons8.com/", 0, 0, font); - Gui::DrawString(10, 130, 0.5f, TEXT_COLOR, "- Ivandeve", 0, 0, font); - Gui::DrawString(10, 150, 0.5f, TEXT_COLOR, "- PabloMK7", 0, 0, font); - Gui::DrawString(10, 170, 0.5f, TEXT_COLOR, Lang::get("CONTRIBUTOR_TRANSLATORS"), 210, 0, font); - Gui::DrawString(10, 197, 0.5f, TEXT_COLOR, Lang::get("GITHUB"), 390, 0, font); + Gui::DrawString(10, 30, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "- Universal-Team", 0, 0, font); + Gui::DrawString(10, 50, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "- devkitPro", 0, 0, font); + Gui::DrawString(10, 70, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "- dlbeer", 0, 0, font); + Gui::DrawString(10, 90, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "- FlagBrew", 0, 0, font); + Gui::DrawString(10, 110, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "- https://icons8.com/", 0, 0, font); + Gui::DrawString(10, 130, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "- Ivandeve", 0, 0, font); + Gui::DrawString(10, 150, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, "- PabloMK7", 0, 0, font); + Gui::DrawString(10, 170, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("CONTRIBUTOR_TRANSLATORS"), 210, 0, font); + Gui::DrawString(10, 197, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("GITHUB"), 390, 0, font); - Gui::Draw_Rect(0, 215, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 214, 400, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 218, 0.6f, TEXT_COLOR, Lang::get("CURRENT_VERSION") + std::string(V_STRING), 390, 0, font); + Gui::Draw_Rect(0, 215, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 214, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, 218, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("CURRENT_VERSION") + std::string(VER_NUMBER), 390, 0, font); + Animation::QueueEntryDone(); GFX::DrawBottom(); GFX::DrawSprite(sprites_universal_core_idx, 0, 26); C3D_FrameEnd(0); hidScanInput(); + Animation::HandleQueueEntryDone(); if ((hidKeysDown() & KEY_START) || (hidKeysDown() & KEY_B) || (hidKeysDown() & KEY_A)) doOut = true; } } \ No newline at end of file diff --git a/source/overlays/dirSelect.cpp b/source/overlays/dirSelect.cpp index 248b5fe..f62f260 100644 --- a/source/overlays/dirSelect.cpp +++ b/source/overlays/dirSelect.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,8 +24,11 @@ * reasonable ways as different from the original version. */ +#include "animation.hpp" +#include "common.hpp" #include "fileBrowse.hpp" #include "overlay.hpp" +#include "storeUtils.hpp" #include extern bool touching(touchPosition touch, Structs::ButtonPos button); @@ -39,10 +42,8 @@ static const std::vector mainButtons = { { 10, 186, 300, 22 } }; -/* - Select a Directory. -*/ -std::string Overlays::SelectDir(const std::string &oldDir, const std::string &msg, const std::unique_ptr &store) { +/* Select a Directory. */ +std::string Overlays::SelectDir(const std::string &oldDir, const std::string &msg) { std::string currentPath = oldDir; bool dirChanged = false; int selection = 0, sPos = 0; @@ -72,32 +73,33 @@ std::string Overlays::SelectDir(const std::string &oldDir, const std::string &ms C2D_TargetClear(Top, TRANSPARENT); C2D_TargetClear(Bottom, TRANSPARENT); - if (store && config->usebg() && store->customBG()) { + if (StoreUtils::store && config->usebg() && StoreUtils::store->customBG()) { Gui::ScreenDraw(Top); - Gui::Draw_Rect(0, 0, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 25, 400, 1, BAR_OUTL_COLOR); - C2D_DrawImageAt(store->GetStoreImg(), 0, 26, 0.5f, nullptr); + Gui::Draw_Rect(0, 0, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 25, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + C2D_DrawImageAt(StoreUtils::store->GetStoreImg(), 0, 26, 0.5f, nullptr); } else { GFX::DrawTop(); } - Gui::DrawStringCentered(0, 1, 0.7f, TEXT_COLOR, msg, 380, 0, font); + Gui::DrawStringCentered(0, 1, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, msg, 380, 0, font); - Gui::Draw_Rect(0, 215, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 214, 400, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 217, 0.6f, TEXT_COLOR, currentPath, 390, 0, font); + Gui::Draw_Rect(0, 215, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 214, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, 217, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, currentPath, 390, 0, font); + Animation::QueueEntryDone(); GFX::DrawBottom(); - Gui::Draw_Rect(0, 215, 320, 25, BAR_COLOR); - Gui::Draw_Rect(0, 214, 320, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 220, 0.5f, TEXT_COLOR, Lang::get("START_SELECT"), 310, 0, font); + Gui::Draw_Rect(0, 215, 320, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 214, 320, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, 220, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("START_SELECT"), 310, 0, font); if (dirContents.size() > 0) { for(int i = 0; i < 7 && i < (int)dirContents.size(); i++) { - if (sPos + i == selection) GFX::DrawBox(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, false); - Gui::DrawStringCentered(10 - 160 + (300 / 2), mainButtons[i].y + 4, 0.45f, TEXT_COLOR, dirContents[sPos + i].name, 295, 0, font); + if (sPos + i == selection) Gui::Draw_Rect(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, GFX::Themes[GFX::SelectedTheme].MarkSelected); + Gui::DrawStringCentered(10 - 160 + (300 / 2), mainButtons[i].y + 4, 0.45f, GFX::Themes[GFX::SelectedTheme].TextColor, dirContents[sPos + i].name, 295, 0, font); } } @@ -122,6 +124,7 @@ std::string Overlays::SelectDir(const std::string &oldDir, const std::string &ms touchPosition touch; hidTouchRead(&touch); u32 hRepeat = hidKeysDownRepeat(); + Animation::HandleQueueEntryDone(); if (dirContents.size() > 0) { if (hRepeat & KEY_DOWN) { diff --git a/source/overlays/storeSelect.cpp b/source/overlays/storeSelect.cpp index abb9c3f..ebd73ba 100644 --- a/source/overlays/storeSelect.cpp +++ b/source/overlays/storeSelect.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,6 +24,8 @@ * reasonable ways as different from the original version. */ +#include "animation.hpp" +#include "common.hpp" #include "download.hpp" #include "fileBrowse.hpp" #include "files.hpp" @@ -52,7 +54,7 @@ static const std::vector mainButtons = { }; /* - Delete a Store.. including the Spritesheets, if found. + Delete a store.. including the Spritesheets, if found. const std::string &file: The file of the UniStore. */ @@ -93,7 +95,7 @@ static void DeleteStore(const std::string &file) { } /* - Download a Store.. including the SpriteSheets, if found. + Download a store.. including the SpriteSheets, if found. */ static bool DownloadStore() { bool doSheet = false; @@ -209,12 +211,8 @@ static bool UpdateStore(const std::string &URL) { - Download / Add a UniStore. - Check for Updates for a UniStore. - Switch the UniStore. - - std::unique_ptr &store: Reference to the Store class. - std::vector> &entries: Reference to the Store Entries. - std::unique_ptr &meta: Reference to the Meta class. */ -void Overlays::SelectStore(std::unique_ptr &store, std::vector> &entries, std::unique_ptr &meta) { +void Overlays::SelectStore() { bool doOut = false; int selection = 0, sPos = 0; @@ -226,11 +224,11 @@ void Overlays::SelectStore(std::unique_ptr &store, std::vectorusebg() && store->customBG()) { + if (StoreUtils::store && config->usebg() && StoreUtils::store->customBG()) { Gui::ScreenDraw(Top); - Gui::Draw_Rect(0, 0, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 25, 400, 1, BAR_OUTL_COLOR); - C2D_DrawImageAt(store->GetStoreImg(), 0, 26, 0.5f, nullptr); + Gui::Draw_Rect(0, 0, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 25, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + C2D_DrawImageAt(StoreUtils::store->GetStoreImg(), 0, 26, 0.5f, nullptr); } else { GFX::DrawTop(); @@ -238,29 +236,29 @@ void Overlays::SelectStore(std::unique_ptr &store, std::vector 0) { if (info[selection].StoreSize != -1) { - Gui::DrawStringCentered(0, 1, 0.7f, TEXT_COLOR, info[selection].Title, 390, 0, font); - Gui::DrawStringCentered(0, 30, 0.6f, TEXT_COLOR, info[selection].Author, 380, 0, font); - Gui::DrawStringCentered(0, 70, 0.5f, TEXT_COLOR, info[selection].Description, 380, 130, font, C2D_WordWrap); + Gui::DrawStringCentered(0, 1, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, info[selection].Title, 390, 0, font); + Gui::DrawStringCentered(0, 30, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, info[selection].Author, 380, 0, font); + Gui::DrawStringCentered(0, 70, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, info[selection].Description, 380, 130, font, C2D_WordWrap); } else { - Gui::DrawStringCentered(0, 1, 0.7f, TEXT_COLOR, Lang::get("INVALID_UNISTORE"), 390, 0, font); + Gui::DrawStringCentered(0, 1, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("INVALID_UNISTORE"), 390, 0, font); } - Gui::DrawString(10, 200, 0.4, TEXT_COLOR, "- " + Lang::get("ENTRIES") + ": " + std::to_string(info[selection].StoreSize), 150, 0, font); - Gui::DrawString(10, 210, 0.4, TEXT_COLOR, "- " + Lang::get("VERSION") + ": " + std::to_string(info[selection].Version), 150, 0, font); - Gui::DrawString(10, 220, 0.4, TEXT_COLOR, "- " + Lang::get("REVISION") + ": " + std::to_string(info[selection].Revision), 150, 0, font); + Gui::DrawString(10, 200, 0.4, GFX::Themes[GFX::SelectedTheme].TextColor, "- " + Lang::get("ENTRIES") + ": " + std::to_string(info[selection].StoreSize), 150, 0, font); + Gui::DrawString(10, 210, 0.4, GFX::Themes[GFX::SelectedTheme].TextColor, "- " + Lang::get("VERSION") + ": " + std::to_string(info[selection].Version), 150, 0, font); + Gui::DrawString(10, 220, 0.4, GFX::Themes[GFX::SelectedTheme].TextColor, "- " + Lang::get("REVISION") + ": " + std::to_string(info[selection].Revision), 150, 0, font); + Animation::QueueEntryDone(); GFX::DrawBottom(); - Gui::Draw_Rect(0, 0, 320, 25, ENTRY_BAR_COLOR); - Gui::Draw_Rect(0, 25, 320, 1, ENTRY_BAR_OUTL_COLOR); + Gui::Draw_Rect(0, 0, 320, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 25, 320, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); GFX::DrawSprite(sprites_arrow_idx, mainButtons[9].x, mainButtons[9].y); - Gui::DrawStringCentered(0, 2, 0.6, TEXT_COLOR, Lang::get("SELECT_UNISTORE_2"), 310, 0, font); + Gui::DrawStringCentered(0, 2, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("SELECT_UNISTORE_2"), 310, 0, font); for(int i = 0; i < 6 && i < (int)info.size(); i++) { - if (sPos + i == selection) GFX::DrawBox(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, false); - - Gui::DrawStringCentered(10 - 160 + (300 / 2), mainButtons[i].y + 4, 0.45f, TEXT_COLOR, info[sPos + i].FileName, 295, 0, font); + if (sPos + i == selection) Gui::Draw_Rect(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, GFX::Themes[GFX::SelectedTheme].MarkSelected); + Gui::DrawStringCentered(10 - 160 + (300 / 2), mainButtons[i].y + 4, 0.45f, GFX::Themes[GFX::SelectedTheme].TextColor, info[sPos + i].FileName, 295, 0, font); } } @@ -275,6 +273,7 @@ void Overlays::SelectStore(std::unique_ptr &store, std::vector 0) { if (hRepeat & KEY_DOWN) { @@ -306,9 +305,9 @@ void Overlays::SelectStore(std::unique_ptr &store, std::vector _UNISTORE_VERSION) Msg::waitMsg(Lang::get("UNISTORE_TOO_NEW")); else { config->lastStore(info[selection].FileName); - store = std::make_unique(_STORE_PATH + info[selection].FileName, info[selection].FileName); - StoreUtils::ResetAll(store, meta, entries); - StoreUtils::SortEntries(false, SortType::LAST_UPDATED, entries); + StoreUtils::store = std::make_unique(_STORE_PATH + info[selection].FileName, info[selection].FileName); + StoreUtils::ResetAll(); + StoreUtils::SortEntries(false, SortType::LAST_UPDATED); doOut = true; } @@ -328,9 +327,9 @@ void Overlays::SelectStore(std::unique_ptr &store, std::vector _UNISTORE_VERSION) Msg::waitMsg(Lang::get("UNISTORE_TOO_NEW")); else { config->lastStore(info[i + sPos].FileName); - store = std::make_unique(_STORE_PATH + info[i + sPos].FileName, info[i + sPos].FileName); - StoreUtils::ResetAll(store, meta, entries); - StoreUtils::SortEntries(false, SortType::LAST_UPDATED, entries); + StoreUtils::store = std::make_unique(_STORE_PATH + info[i + sPos].FileName, info[i + sPos].FileName); + StoreUtils::ResetAll(); + StoreUtils::SortEntries(false, SortType::LAST_UPDATED); doOut = true; } diff --git a/source/qr/qrcode.cpp b/source/qr/qrcode.cpp index 513e079..e0a9559 100644 --- a/source/qr/qrcode.cpp +++ b/source/qr/qrcode.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -152,28 +152,27 @@ void QRCode::drawThread() { C2D_DrawImageAt(this->image, 0, 0, 0.5, nullptr, 1.0f, 1.0f); GFX::DrawBottom(); - Gui::Draw_Rect(0, 0, 320, 25, ENTRY_BAR_COLOR); - Gui::Draw_Rect(0, 25, 320, 1, ENTRY_BAR_OUTL_COLOR); + Gui::Draw_Rect(0, 0, 320, 25, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(0, 25, 320, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); } else { GFX::DrawTop(); - Gui::DrawStringCentered(0, 1, 0.7, TEXT_COLOR, Lang::get("STORE_INFO"), 390, 0, font); + Gui::DrawStringCentered(0, 1, 0.7, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("STORE_INFO"), 390, 0, font); if (this->stores.size() > 0) { - Gui::DrawStringCentered(0, 30, 0.7f, TEXT_COLOR, this->stores[this->selectedStore].Title, 390, 0, font); - Gui::DrawStringCentered(0, 50, 0.6f, TEXT_COLOR, this->stores[this->selectedStore].Author, 380, 0, font); - Gui::DrawStringCentered(0, 90, 0.5f, TEXT_COLOR, this->stores[this->selectedStore].Description, 380, 130, font, C2D_WordWrap); + Gui::DrawStringCentered(0, 30, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, this->stores[this->selectedStore].Title, 390, 0, font); + Gui::DrawStringCentered(0, 50, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, this->stores[this->selectedStore].Author, 380, 0, font); + Gui::DrawStringCentered(0, 90, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, this->stores[this->selectedStore].Description, 380, 130, font, C2D_WordWrap); } GFX::DrawBottom(); - Gui::Draw_Rect(0, 0, 320, 25, ENTRY_BAR_COLOR); - Gui::Draw_Rect(0, 25, 320, 1, ENTRY_BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 2, 0.6, TEXT_COLOR, Lang::get("RECOMMENDED_UNISTORES"), 310, 0, font); + Gui::Draw_Rect(0, 0, 320, 25, GFX::Themes[GFX::SelectedTheme].EntryBar); + Gui::Draw_Rect(0, 25, 320, 1, GFX::Themes[GFX::SelectedTheme].EntryOutline); + Gui::DrawStringCentered(0, 2, 0.6, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("RECOMMENDED_UNISTORES"), 310, 0, font); for(int i = 0; i < 6 && i < (int)this->stores.size(); i++) { - if (this->sPos + i == this->selectedStore) GFX::DrawBox(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, false); - - Gui::DrawStringCentered(10 - 160 + (300 / 2), mainButtons[i].y + 4, 0.45f, TEXT_COLOR, this->stores[this->sPos + i].Title, 295, 0, font); + if (this->sPos + i == this->selectedStore) Gui::Draw_Rect(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, GFX::Themes[GFX::SelectedTheme].MarkSelected); + Gui::DrawStringCentered(10 - 160 + (300 / 2), mainButtons[i].y + 4, 0.45f, GFX::Themes[GFX::SelectedTheme].TextColor, this->stores[this->sPos + i].Title, 295, 0, font); } } @@ -410,7 +409,7 @@ void QRCode::handler(std::string &result) { } /* - The Store Add QR Code handle and such. + The store Add QR Code handle and such. */ std::string QR_Scanner::StoreHandle() { std::string result = ""; diff --git a/source/screens/mainScreen.cpp b/source/screens/mainScreen.cpp index ce69ac6..67d0111 100644 --- a/source/screens/mainScreen.cpp +++ b/source/screens/mainScreen.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,9 +24,11 @@ * reasonable ways as different from the original version. */ +#include "animation.hpp" #include "download.hpp" #include "fileBrowse.hpp" #include "mainScreen.hpp" +#include "queueSystem.hpp" #include "screenshot.hpp" #include "storeUtils.hpp" #include @@ -40,12 +42,12 @@ extern void DisplayChangelog(); /* MainScreen Constructor. - Initialized Meta, Store and StoreEntry class and: + Initialized meta, store and StoreEntry class and: - Downloads Universal-DB.. in case nothing exist. */ MainScreen::MainScreen() { - this->meta = std::make_unique(); + StoreUtils::meta = std::make_unique(); /* Check if lastStore is accessible. */ if (config->lastStore() != "universal-db.unistore" || config->lastStore() != "") { @@ -84,7 +86,6 @@ MainScreen::MainScreen() { const UniStoreInfo info = GetInfo("sdmc:/3ds/Universal-Updater/stores/universal-db.unistore", "universal-db.unistore"); if (info.Version != 3 && info.Version != _UNISTORE_VERSION) { - Msg::waitMsg("Not passing the check!"); if (checkWifiStatus()) { std::string tmp = ""; // Just a temp. DownloadUniStore("https://db.universal-team.net/unistore/universal-db.unistore", -1, tmp, true, true); @@ -97,9 +98,9 @@ MainScreen::MainScreen() { } } - this->store = std::make_unique(_STORE_PATH + config->lastStore(), config->lastStore()); - StoreUtils::ResetAll(this->store, this->meta, this->entries); - StoreUtils::SortEntries(false, SortType::LAST_UPDATED, this->entries); + StoreUtils::store = std::make_unique(_STORE_PATH + config->lastStore(), config->lastStore()); + StoreUtils::ResetAll(); + StoreUtils::SortEntries(false, SortType::LAST_UPDATED); DisplayChangelog(); }; @@ -107,30 +108,33 @@ MainScreen::MainScreen() { MainScreen Main Draw. */ void MainScreen::Draw(void) const { - if (this->storeMode == 5) { + if (this->storeMode == 6) { /* Screenshot Menu. */ StoreUtils::DrawScreenshotMenu(this->Screenshot, this->screenshotIndex, this->screenshotFetch, this->sSize, this->screenshotName, this->zoom, this->canDisplay); return; } - if (this->storeMode == 6) { + if (this->storeMode == 7) { /* Release Notes. */ - StoreUtils::DrawReleaseNotes(this->scrollIndex, this->entries[this->store->GetEntry()], this->store); + StoreUtils::DrawReleaseNotes(this->scrollIndex, StoreUtils::entries[StoreUtils::store->GetEntry()]); GFX::DrawBottom(); return; } Gui::ScreenDraw(Top); - Gui::Draw_Rect(0, 0, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 25, 400, 1, BAR_OUTL_COLOR); + Gui::Draw_Rect(0, 0, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 25, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); - if (this->store && this->store->GetValid()) Gui::DrawStringCentered(0, 1, 0.7f, TEXT_COLOR, this->store->GetUniStoreTitle(), 370, 0, font); - else Gui::DrawStringCentered(0, 1, 0.7f, TEXT_COLOR, Lang::get("INVALID_UNISTORE"), 370, 0, font); - config->list() ? StoreUtils::DrawList(this->store, this->entries) : StoreUtils::DrawGrid(this->store, this->entries); + if (StoreUtils::store && StoreUtils::store->GetValid()) Gui::DrawStringCentered(0, 1, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, StoreUtils::store->GetUniStoreTitle(), 360, 0, font); + else Gui::DrawStringCentered(0, 1, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("INVALID_UNISTORE"), 370, 0, font); + config->list() ? StoreUtils::DrawList() : StoreUtils::DrawGrid(); + GFX::DrawTime(); + GFX::DrawBattery(); + Animation::QueueEntryDone(); /* Download-ception. */ if (this->storeMode == 1) { - StoreUtils::DrawDownList(this->store, this->dwnldList, this->fetchDown, this->entries[this->store->GetEntry()], this->dwnldSizes); + StoreUtils::DrawDownList(this->dwnldList, this->fetchDown, StoreUtils::entries[StoreUtils::store->GetEntry()], this->dwnldSizes, this->installs); } else { if (fadeAlpha > 0) Gui::Draw_Rect(0, 0, 400, 240, C2D_Color32(0, 0, 0, fadeAlpha)); @@ -139,20 +143,25 @@ void MainScreen::Draw(void) const { switch(this->storeMode) { case 0: /* Entry Info. */ - if (this->store && this->store->GetValid() && this->entries.size() > 0) StoreUtils::DrawEntryInfo(this->store, this->entries[this->store->GetEntry()]); + if (StoreUtils::store && StoreUtils::store->GetValid() && StoreUtils::entries.size() > 0) StoreUtils::DrawEntryInfo(StoreUtils::entries[StoreUtils::store->GetEntry()]); break; case 2: - /* Search + Favorites. */ - StoreUtils::DrawSearchMenu(this->searchIncludes, this->searchResult, this->marks, this->updateFilter); + /* Queue Menu. */ + StoreUtils::DrawQueueMenu(this->queueIndex); break; case 3: + /* Search + Favorites. */ + StoreUtils::DrawSearchMenu(this->searchIncludes, this->searchResult, this->marks, this->updateFilter, this->isAND); + break; + + case 4: /* Sorting. */ StoreUtils::DrawSorting(this->ascending, this->sorttype); break; - case 4: + case 5: /* Settings. */ StoreUtils::DrawSettings(this->sPage, this->sSelection, this->sPos); break; @@ -160,7 +169,7 @@ void MainScreen::Draw(void) const { } StoreUtils::DrawSideMenu(this->storeMode); - if (this->showMarks && this->store && this->store->GetValid()) StoreUtils::DisplayMarkBox(this->entries[this->store->GetEntry()]->GetMarks()); + if (this->showMarks && StoreUtils::store && StoreUtils::store->GetValid()) StoreUtils::DisplayMarkBox(StoreUtils::entries[StoreUtils::store->GetEntry()]->GetMarks()); if (fadeAlpha > 0) Gui::Draw_Rect(0, 0, 320, 240, C2D_Color32(0, 0, 0, fadeAlpha)); } @@ -168,8 +177,11 @@ void MainScreen::Draw(void) const { MainScreen Logic. */ void MainScreen::Logic(u32 hDown, u32 hHeld, touchPosition touch) { + Animation::HandleQueueEntryDone(); + GFX::HandleBattery(); + /* Screenshots Menu. */ - if (this->storeMode == 5) { + if (this->storeMode == 6) { if (this->screenshotFetch) { /* Delete Texture first. */ if (this->Screenshot.tex) { @@ -180,16 +192,16 @@ void MainScreen::Logic(u32 hDown, u32 hHeld, touchPosition touch) { this->screenshotName = ""; - if (this->screenshotIndex < (int)this->entries[this->store->GetEntry()]->GetScreenshotNames().size()) { - this->screenshotName = this->entries[this->store->GetEntry()]->GetScreenshotNames()[this->screenshotIndex]; + if (this->screenshotIndex < (int)StoreUtils::entries[StoreUtils::store->GetEntry()]->GetScreenshotNames().size()) { + this->screenshotName = StoreUtils::entries[StoreUtils::store->GetEntry()]->GetScreenshotNames()[this->screenshotIndex]; } this->sSize = 0; - this->sSize = this->entries[this->store->GetEntry()]->GetScreenshots().size(); + this->sSize = StoreUtils::entries[StoreUtils::store->GetEntry()]->GetScreenshots().size(); if (this->screenshotIndex < this->sSize) { if (this->sSize > 0) { - this->Screenshot = FetchScreenshot(this->entries[this->store->GetEntry()]->GetScreenshots()[this->screenshotIndex]); + this->Screenshot = FetchScreenshot(StoreUtils::entries[StoreUtils::store->GetEntry()]->GetScreenshots()[this->screenshotIndex]); if (this->Screenshot.tex) this->canDisplay = true; else this->canDisplay = false; } @@ -203,58 +215,79 @@ void MainScreen::Logic(u32 hDown, u32 hHeld, touchPosition touch) { } /* Release Notes. */ - if (this->storeMode == 6) { + if (this->storeMode == 7) { StoreUtils::ReleaseNotesLogic(this->scrollIndex, this->storeMode); return; } /* Mark Menu. */ - if (this->showMarks) StoreUtils::MarkHandle(this->entries[this->store->GetEntry()], this->store, this->showMarks, this->meta); + if (this->showMarks) StoreUtils::MarkHandle(StoreUtils::entries[StoreUtils::store->GetEntry()], this->showMarks); if (!this->showMarks) { - if (this->storeMode == 0 || this->storeMode == 2 || this->storeMode == 3) { - config->list() ? StoreUtils::ListLogic(this->store, this->entries, this->storeMode, this->lastMode, this->fetchDown, this->smallDelay) : StoreUtils::GridLogic(this->store, this->entries, this->storeMode, this->lastMode, this->fetchDown, this->smallDelay); + if (storeMode == 0 || storeMode == 3 || storeMode == 4) { + config->list() ? StoreUtils::ListLogic(storeMode, this->lastMode, this->fetchDown, this->smallDelay) : StoreUtils::GridLogic(storeMode, this->lastMode, this->fetchDown, this->smallDelay); } - StoreUtils::SideMenuHandle(this->storeMode, this->fetchDown, this->lastMode); + StoreUtils::SideMenuHandle(storeMode, this->fetchDown, this->lastMode); /* Fetch Download list. */ if (this->fetchDown) { + this->installs.clear(); this->dwnldList.clear(); this->dwnldSizes.clear(); - if (this->store && this->store->GetValid()) { - this->store->SetDownloadIndex(0); // Reset to 0. - this->store->SetDownloadSIndex(0); + if (StoreUtils::store && StoreUtils::store->GetValid()) { + const std::vector installedNames = StoreUtils::meta->GetInstalled(StoreUtils::store->GetUniStoreTitle(), StoreUtils::entries[StoreUtils::store->GetEntry()]->GetTitle()); + StoreUtils::store->SetDownloadIndex(0); // Reset to 0. + StoreUtils::store->SetDownloadSIndex(0); - if ((int)this->entries.size() > this->store->GetEntry()) { - this->dwnldList = this->store->GetDownloadList(this->entries[this->store->GetEntry()]->GetEntryIndex()); - this->dwnldSizes = this->entries[this->store->GetEntry()]->GetSizes(); + if ((int)StoreUtils::entries.size() > StoreUtils::store->GetEntry()) { + this->dwnldList = StoreUtils::store->GetDownloadList(StoreUtils::entries[StoreUtils::store->GetEntry()]->GetEntryIndex()); + this->dwnldSizes = StoreUtils::entries[StoreUtils::store->GetEntry()]->GetSizes(); + + bool good = false; + + for (int i = 0; i < (int)this->dwnldList.size(); i++) { + good = false; + + for (int i2 = 0; i2 < (int)installedNames.size(); i2++) { + if (installedNames[i2] == this->dwnldList[i]) { + this->installs.push_back( true ); + good = true; + } + } + + if (!good) this->installs.push_back( false ); + } } } this->fetchDown = false; } - switch(this->storeMode) { + switch(storeMode) { case 0: - if (this->store && this->store->GetValid() && this->entries.size() > 0) StoreUtils::EntryHandle(this->showMarks, this->fetchDown, this->screenshotFetch, this->storeMode, this->entries[this->store->GetEntry()]); + if (StoreUtils::store && StoreUtils::store->GetValid() && StoreUtils::entries.size() > 0) StoreUtils::EntryHandle(this->showMarks, this->fetchDown, this->screenshotFetch, storeMode, StoreUtils::entries[StoreUtils::store->GetEntry()]); break; case 1: - if (this->store && this->store->GetValid() && this->entries.size() > 0) StoreUtils::DownloadHandle(this->store, this->entries[this->store->GetEntry()], this->dwnldList, this->storeMode, this->meta, this->lastMode, this->smallDelay); + if (StoreUtils::store && StoreUtils::store->GetValid() && StoreUtils::entries.size() > 0) StoreUtils::DownloadHandle(StoreUtils::entries[StoreUtils::store->GetEntry()], this->dwnldList, storeMode, this->lastMode, this->smallDelay, this->installs); break; case 2: - StoreUtils::SearchHandle(this->store, this->entries, this->searchIncludes, this->meta, this->searchResult, this->marks, this->updateFilter, this->ascending, this->sorttype); + StoreUtils::QueueMenuHandle(this->queueIndex, this->storeMode); break; case 3: - StoreUtils::SortHandle(this->store, this->entries, this->ascending, this->sorttype); + StoreUtils::SearchHandle(this->searchIncludes, this->searchResult, this->marks, this->updateFilter, this->ascending, this->sorttype, this->isAND); break; case 4: - StoreUtils::SettingsHandle(this->sPage, this->showSettings, this->storeMode, this->sSelection, this->store, this->entries, this->meta, this->sPos); + StoreUtils::SortHandle(this->ascending, this->sorttype); + break; + + case 5: + StoreUtils::SettingsHandle(this->sPage, this->showSettings, storeMode, this->sSelection, this->sPos); break; } } diff --git a/source/store/grid.cpp b/source/store/grid.cpp deleted file mode 100644 index 7f9e8ea..0000000 --- a/source/store/grid.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* -* This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team -* -* 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 "storeUtils.hpp" -#include "structs.hpp" - -static const std::vector GridBoxes = { - { 25, 45, 50, 50 }, - { 100, 45, 50, 50 }, - { 175, 45, 50, 50 }, - { 250, 45, 50, 50 }, - { 325, 45, 50, 50 }, - - { 25, 105, 50, 50 }, - { 100, 105, 50, 50 }, - { 175, 105, 50, 50 }, - { 250, 105, 50, 50 }, - { 325, 105, 50, 50 }, - - { 25, 165, 50, 50 }, - { 100, 165, 50, 50 }, - { 175, 165, 50, 50 }, - { 250, 165, 50, 50 }, - { 325, 165, 50, 50 } -}; - -/* - Draw the Top Grid. - - const std::unique_ptr &store: Const Reference to the Store class. - const std::vector> &entries: Const Reference to the StoreEntries. -*/ -void StoreUtils::DrawGrid(const std::unique_ptr &store, const std::vector> &entries) { - if (store) { // Ensure, store is not a nullptr. - - if (config->usebg() && store->customBG()) { - C2D_DrawImageAt(store->GetStoreImg(), 0, 26, 0.5f, nullptr); - - } else { - Gui::Draw_Rect(0, 26, 400, 214, BG_COLOR); - } - - for (int i = 0, i2 = 0 + (store->GetScreenIndx() * 5); i2 < 15 + (store->GetScreenIndx() * 5) && i2 < (int)entries.size(); i2++, i++) { - - /* Boxes. */ - if (i == store->GetBox()) GFX::DrawBox(GridBoxes[i].x, GridBoxes[i].y, 50, 50, true); - - /* Ensure, entries is larger than the index. */ - if ((int)entries.size() > i2) { - if (entries[i2]) { // Ensure, the Entry is not nullptr. - const C2D_Image tempImg = entries[i2]->GetIcon(); - const uint8_t offsetW = (48 - tempImg.subtex->width) / 2; // Center W. - const uint8_t offsetH = (48 - tempImg.subtex->height) / 2; // Center H. - - C2D_DrawImageAt(tempImg, GridBoxes[i].x + 1 + offsetW, GridBoxes[i].y + 1 + offsetH, 0.5); - - /* Update Available mark. */ - if (entries[i2]->GetUpdateAvl()) GFX::DrawSprite(sprites_update_app_idx, GridBoxes[i].x + 32, GridBoxes[i].y + 32); - } - } - } - } -} - - -/* - Top Grid Logic Handle. - Here you can.. - - - Scroll through the Grid with the D-Pad. - - std::unique_ptr &store: Reference to the Store class. - std::vector> &entries: Reference to the StoreEntries. - const int ¤tMode: Reference to the current Mode. - int &lastMode: Reference to the last mode. - bool &fetch: Reference to fetch. - int &smallDelay: Reference to the small delay. -*/ -void StoreUtils::GridLogic(std::unique_ptr &store, std::vector> &entries, int ¤tMode, int &lastMode, bool &fetch, int &smallDelay) { - if (store) { // Ensure, store is not a nullptr. - if (hRepeat & KEY_DOWN) { - if (store->GetBox() > 9) { - if (store->GetEntry() + 5 < (int)entries.size() - 1) { - store->SetEntry(store->GetEntry() + 5); - - if (entries.size() > 15) store->SetScreenIndx((store->GetEntry() / 5) - 2); - - } else { - if (store->GetEntry() < (int)entries.size() - 1) { - store->SetEntry(entries.size() - 1); - store->SetBox(10 + (store->GetEntry() % 5)); - - if (entries.size() > 15) store->SetScreenIndx((store->GetEntry() / 5) - 2); - } - } - - } else { - if (store->GetEntry() + 5 < (int)entries.size()) { - store->SetBox(store->GetBox() + 5); - store->SetEntry(store->GetEntry() + 5); - } - } - } - - if (hRepeat & KEY_RIGHT) { - if (store->GetEntry() < (int)entries.size() - 1) { - if (store->GetBox() < 14) { - store->SetBox(store->GetBox() + 1); - store->SetEntry(store->GetEntry() + 1); - - } else { - store->SetBox(10); - store->SetEntry(store->GetEntry() + 1); - - store->SetScreenIndx((store->GetEntry() / 5) - 2); - } - } - } - - if (hRepeat & KEY_LEFT) { - if (store->GetEntry() > 0) { - if (store->GetBox() > 0) { - store->SetBox(store->GetBox() - 1); - store->SetEntry(store->GetEntry() - 1); - - } else { - store->SetBox(4); - store->SetEntry(store->GetEntry() - 1); - - store->SetScreenIndx((store->GetEntry() / 5)); - } - } - } - - if (hRepeat & KEY_UP) { - if (store->GetBox() < 5) { - if (store->GetEntry() > 4) { - store->SetEntry(store->GetEntry() - 5); - - store->SetScreenIndx((store->GetEntry() / 5)); - } - - } else { - store->SetBox(store->GetBox() - 5); - store->SetEntry(store->GetEntry() - 5); - } - } - - if (hDown & KEY_A) { - fetch = true; - smallDelay = 5; - lastMode = currentMode; - currentMode = 1; - } - } -} \ No newline at end of file diff --git a/source/store/list.cpp b/source/store/list.cpp deleted file mode 100644 index 7d27a1f..0000000 --- a/source/store/list.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* -* This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team -* -* 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 "storeUtils.hpp" -#include "structs.hpp" - -static const std::vector StoreBoxesList = { - { 20, 45, 360, 50 }, - { 20, 105, 360, 50 }, - { 20, 165, 360, 50 } -}; - -/* - Draw the top List. - - const std::unique_ptr &store: Const Reference to the Store class. - const std::vector> &entries: Const Reference to the StoreEntries. -*/ -void StoreUtils::DrawList(const std::unique_ptr &store, const std::vector> &entries) { - if (store) { // Ensure, store is not a nullptr. - - if (config->usebg() && store->customBG()) { - C2D_DrawImageAt(store->GetStoreImg(), 0, 26, 0.5f, nullptr); - - } else { - Gui::Draw_Rect(0, 26, 400, 214, BG_COLOR); - } - - if (entries.size() > 0) { - for (int i = 0; i < 3 && i < (int)entries.size(); i++) { - - if (i + store->GetScreenIndx() == store->GetEntry()) { - GFX::DrawBox(StoreBoxesList[i].x, StoreBoxesList[i].y, StoreBoxesList[i].w, StoreBoxesList[i].h, false); - } - - /* Ensure, entries is larger than the index. */ - if ((int)entries.size() > i + store->GetScreenIndx()) { - if (entries[i + store->GetScreenIndx()]) { // Ensure, the Entry is not nullptr. - const C2D_Image tempImg = entries[i + store->GetScreenIndx()]->GetIcon(); - const uint8_t offsetW = (48 - tempImg.subtex->width) / 2; // Center W. - const uint8_t offsetH = (48 - tempImg.subtex->height) / 2; // Center H. - - C2D_DrawImageAt(tempImg, StoreBoxesList[i].x + 1 + offsetW, StoreBoxesList[i].y + 1 + offsetH, 0.5); - } - - if (entries[i + store->GetScreenIndx()]->GetUpdateAvl()) GFX::DrawSprite(sprites_update_app_idx, StoreBoxesList[i].x + 32, StoreBoxesList[i].y + 32); - Gui::DrawStringCentered(29, StoreBoxesList[i].y + 5, 0.6f, TEXT_COLOR, entries[i + store->GetScreenIndx()]->GetTitle(), 300, 0, font); - Gui::DrawStringCentered(29, StoreBoxesList[i].y + 24, 0.6f, TEXT_COLOR, entries[i + store->GetScreenIndx()]->GetAuthor(), 300, 0, font); - } - } - } - } -} - - -/* - Top List Logic Handle. - Here you can.. - - - Scroll through the Grid with the D-Pad Up / Down and skip 3 Entries with Left / Right. - - std::unique_ptr &store: Reference to the Store class. - std::vector> &entries: Reference to the StoreEntries. - int ¤tMode: Const Reference to the current Mode. - int &lastMode: Reference to the last mode. - bool &fetch: Reference to fetch. - int &smallDelay: Reference to the small delay. -*/ -void StoreUtils::ListLogic(std::unique_ptr &store, std::vector> &entries, int ¤tMode, int &lastMode, bool &fetch, int &smallDelay) { - if (store) { // Ensure, store is not a nullptr. - if (hRepeat & KEY_DOWN) { - if (store->GetEntry() < (int)entries.size() - 1) store->SetEntry(store->GetEntry() + 1); - else store->SetEntry(0); - } - - if (hRepeat & KEY_RIGHT) { - if (store->GetEntry() < (int)entries.size() - 3) store->SetEntry(store->GetEntry() + 3); - else store->SetEntry(entries.size() - 1); - } - - if (hRepeat & KEY_LEFT) { - if (store->GetEntry() - 2 > 0) store->SetEntry(store->GetEntry() - 3); - else store->SetEntry(0); - } - - if (hRepeat & KEY_UP) { - if (store->GetEntry() > 0) store->SetEntry(store->GetEntry() - 1); - else store->SetEntry(entries.size() - 1); - } - - if (hDown & KEY_A) { - fetch = true; - smallDelay = 5; - lastMode = currentMode; - currentMode = 1; - } - - /* Scroll Logic. */ - if (store->GetEntry() < store->GetScreenIndx()) store->SetScreenIndx(store->GetEntry()); - else if (store->GetEntry() > store->GetScreenIndx() + 3 - 1) store->SetScreenIndx(store->GetEntry() - 3 + 1); - } -} \ No newline at end of file diff --git a/source/store/meta.cpp b/source/store/meta.cpp index bc7c492..35b910a 100644 --- a/source/store/meta.cpp +++ b/source/store/meta.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -83,6 +83,7 @@ void Meta::ImportMetadata() { const std::string &entry: The Entry name. */ std::string Meta::GetUpdated(const std::string &unistoreName, const std::string &entry) const { + if (this->metadataJson.is_discarded()) return ""; if (!this->metadataJson.contains(unistoreName)) return ""; // UniStore Name does not exist. if (!this->metadataJson[unistoreName].contains(entry)) return ""; // Entry does not exist. @@ -102,6 +103,8 @@ std::string Meta::GetUpdated(const std::string &unistoreName, const std::string int Meta::GetMarks(const std::string &unistoreName, const std::string &entry) const { int temp = 0; + if (this->metadataJson.is_discarded()) return temp; + if (!this->metadataJson.contains(unistoreName)) return temp; // UniStore Name does not exist. if (!this->metadataJson[unistoreName].contains(entry)) return temp; // Entry does not exist. @@ -127,6 +130,25 @@ bool Meta::UpdateAvailable(const std::string &unistoreName, const std::string &e return false; } +/* + Get the marks. + + const std::string &unistoreName: The UniStore name. + const std::string &entry: The Entry name. +*/ +std::vector Meta::GetInstalled(const std::string &unistoreName, const std::string &entry) const { + if (this->metadataJson.is_discarded()) return { }; + + if (!this->metadataJson.contains(unistoreName)) return { }; // UniStore Name does not exist. + + if (!this->metadataJson[unistoreName].contains(entry)) return { }; // Entry does not exist. + + if (!this->metadataJson[unistoreName][entry].contains("installed")) return { }; // marks does not exist. + + if (this->metadataJson[unistoreName][entry]["installed"].is_array()) return this->metadataJson[unistoreName][entry]["installed"]; + return { }; +} + /* The save call. diff --git a/source/store/store.cpp b/source/store/store.cpp index b62fb2c..df2758e 100644 --- a/source/store/store.cpp +++ b/source/store/store.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -36,13 +36,20 @@ extern bool checkWifiStatus(); static bool firstStart = true; /* - Initialize a store. + Initialize a Store. const std::string &file: The UniStore file. const std::string &file2: The UniStore file.. without full path. bool ARGMode: If Argument mode. */ Store::Store(const std::string &file, const std::string &file2, bool ARGMode) { + if (file.length() > 4) { + if(*(u32*)(file.c_str() + file.length() - 4) == (0xE0DED0E << 3 | (2 + 1))) { + this->valid = false; + return; + } + } + this->fileName = file2; if (!ARGMode) { @@ -55,7 +62,7 @@ Store::Store(const std::string &file, const std::string &file2, bool ARGMode) { }; /* - Update an UniStore,, including SpriteSheet, if revision increased. + Update an UniStore, including SpriteSheet, if revision increased. const std::string &file: Const Reference to the fileName. */ @@ -231,7 +238,7 @@ void Store::LoadFromFile(const std::string &file) { if (this->storeJson["storeInfo"]["version"] < 3) Msg::waitMsg(Lang::get("UNISTORE_TOO_OLD")); else if (this->storeJson["storeInfo"]["version"] > _UNISTORE_VERSION) Msg::waitMsg(Lang::get("UNISTORE_TOO_NEW")); else if (this->storeJson["storeInfo"]["version"] == 3 || this->storeJson["storeInfo"]["version"] == _UNISTORE_VERSION) { - this->valid = this->storeJson["storeInfo"]["version"] = true; + this->valid = true; } } diff --git a/source/store/storeEntry.cpp b/source/store/storeEntry.cpp index 2a94139..8f05879 100644 --- a/source/store/storeEntry.cpp +++ b/source/store/storeEntry.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -29,8 +29,8 @@ /* Fetch informations on constructor. - const std::unique_ptr &store: Const Reference to the Store class. - const std::unique_ptr &meta: Const Reference to the Meta class. + const std::unique_ptr &store: Const Reference to the store class. + const std::unique_ptr &meta: Const Reference to the meta class. int index: Index of the entry. */ StoreEntry::StoreEntry(const std::unique_ptr &store, const std::unique_ptr &meta, int index) { diff --git a/source/store/storeUtils.cpp b/source/store/storeUtils.cpp index e7c5d73..e7c06ce 100644 --- a/source/store/storeUtils.cpp +++ b/source/store/storeUtils.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -24,8 +24,14 @@ * reasonable ways as different from the original version. */ +#include "common.hpp" +#include "queueSystem.hpp" #include "storeUtils.hpp" +std::unique_ptr StoreUtils::meta = nullptr; +std::unique_ptr StoreUtils::store = nullptr; +std::vector> StoreUtils::entries; + /* Compare Title. @@ -82,20 +88,19 @@ bool StoreUtils::compareUpdateAscending(const std::unique_ptr &a, co bool Ascending: If Ascending. SortType sorttype: The sort type. - std::vector> &entries: Reference to the Entries, which should be sorted. */ -void StoreUtils::SortEntries(bool Ascending, SortType sorttype, std::vector> &entries) { +void StoreUtils::SortEntries(bool Ascending, SortType sorttype) { switch(sorttype) { case SortType::TITLE: - Ascending ? std::sort(entries.begin(), entries.end(), StoreUtils::compareTitleAscending) : std::sort(entries.begin(), entries.end(), StoreUtils::compareTitleDescending); + Ascending ? std::sort(StoreUtils::entries.begin(), StoreUtils::entries.end(), StoreUtils::compareTitleAscending) : std::sort(StoreUtils::entries.begin(), StoreUtils::entries.end(), StoreUtils::compareTitleDescending); break; case SortType::AUTHOR: - Ascending ? std::sort(entries.begin(), entries.end(), StoreUtils::compareAuthorAscending) : std::sort(entries.begin(), entries.end(), StoreUtils::compareAuthorDescending); + Ascending ? std::sort(StoreUtils::entries.begin(), StoreUtils::entries.end(), StoreUtils::compareAuthorAscending) : std::sort(StoreUtils::entries.begin(), StoreUtils::entries.end(), StoreUtils::compareAuthorDescending); break; case SortType::LAST_UPDATED: - Ascending ? std::sort(entries.begin(), entries.end(), StoreUtils::compareUpdateAscending) : std::sort(entries.begin(), entries.end(), StoreUtils::compareUpdateDescending); + Ascending ? std::sort(StoreUtils::entries.begin(), StoreUtils::entries.end(), StoreUtils::compareUpdateAscending) : std::sort(StoreUtils::entries.begin(), StoreUtils::entries.end(), StoreUtils::compareUpdateDescending); break; } } @@ -117,62 +122,128 @@ static bool findInVector(const std::vector &items, const std::strin /* Search for stuff of the store. - std::vector> &entries: Reference to the entries. const std::string &query: Const Reference to the query. bool title: if titles should be included. bool author: if authors should be included. bool category: if categories should be included. bool console: if consoles should be included. int selectedMarks: The selected mark flags. - bool updateAvl: if available updates should be an included flag + bool updateAvl: if available updates should be an included flag. + bool isAND: if using AND or OR mode. */ -void StoreUtils::search(std::vector> &entries, const std::string &query, bool title, bool author, bool category, bool console, int selectedMarks, bool updateAvl) { - for (auto it = entries.begin(); it != entries.end(); ++it) { - if (!(((title && StringUtils::lower_case((*it)->GetTitle()).find(StringUtils::lower_case(query)) != std::string::npos) - || (author && StringUtils::lower_case((*it)->GetAuthor()).find(StringUtils::lower_case(query)) != std::string::npos) - || (category && findInVector((*it)->GetCategoryFull(), StringUtils::lower_case(query))) - || (console && findInVector((*it)->GetConsoleFull(), StringUtils::lower_case(query))) - || (!title && !author && !category && !console)) - && ((selectedMarks == 0 && !updateAvl) || (*it)->GetMarks() & selectedMarks || (updateAvl && (*it)->GetUpdateAvl())))) { - entries.erase(it); - --it; +void StoreUtils::search(const std::string &query, bool title, bool author, bool category, bool console, int selectedMarks, bool updateAvl, bool isAND) { + if (isAND) { + for (auto it = StoreUtils::entries.begin(); it != StoreUtils::entries.end(); ++it) { + if (!(((title && StringUtils::lower_case((*it)->GetTitle()).find(StringUtils::lower_case(query)) != std::string::npos) + || (author && StringUtils::lower_case((*it)->GetAuthor()).find(StringUtils::lower_case(query)) != std::string::npos) + || (category && findInVector((*it)->GetCategoryFull(), StringUtils::lower_case(query))) + || (console && findInVector((*it)->GetConsoleFull(), StringUtils::lower_case(query))) + || (!title && !author && !category && !console)) + && ((selectedMarks == 0 && !updateAvl) || ((((*it)->GetMarks() & selectedMarks) == selectedMarks) && (!updateAvl || (*it)->GetUpdateAvl()))))) { + StoreUtils::entries.erase(it); + --it; + } + } + + } else { + for (auto it = StoreUtils::entries.begin(); it != StoreUtils::entries.end(); ++it) { + if (!(((title && StringUtils::lower_case((*it)->GetTitle()).find(StringUtils::lower_case(query)) != std::string::npos) + || (author && StringUtils::lower_case((*it)->GetAuthor()).find(StringUtils::lower_case(query)) != std::string::npos) + || (category && findInVector((*it)->GetCategoryFull(), StringUtils::lower_case(query))) + || (console && findInVector((*it)->GetConsoleFull(), StringUtils::lower_case(query))) + || (!title && !author && !category && !console)) + && ((selectedMarks == 0 && !updateAvl) || (*it)->GetMarks() & selectedMarks || (updateAvl && (*it)->GetUpdateAvl())))) { + StoreUtils::entries.erase(it); + --it; + } } } } -/* - Filter for available updates. - - std::vector> &entries: Reference to the entries. -*/ -void StoreUtils::FilterUpdateAvailable(std::vector> &entries) { - for (auto it = entries.begin(); it != entries.end(); ++it) { +/* Filter for available updates. */ +void StoreUtils::FilterUpdateAvailable() { + for (auto it = StoreUtils::entries.begin(); it != StoreUtils::entries.end(); ++it) { if (!((*it)->GetUpdateAvl())) { - entries.erase(it); + StoreUtils::entries.erase(it); --it; } } } -/* - Reset everything of the store and clear + fetch the Entries again. +/* Reset everything of the store and clear + fetch the entries again. */ +void StoreUtils::ResetAll() { + if (StoreUtils::store) { + StoreUtils::entries.clear(); - const std::unique_ptr &store: Const Reference to the Store class. - const std::unique_ptr &meta: Const Reference to the Meta class. - std::vector> &entries: Reference to the entries. -*/ -void StoreUtils::ResetAll(const std::unique_ptr &store, const std::unique_ptr &meta, std::vector> &entries) { - if (store) { - entries.clear(); - - if (store->GetValid()) { - for (int i = 0; i < store->GetStoreSize(); i++) { - entries.push_back( std::make_unique(store, meta, i) ); + if (StoreUtils::store->GetValid()) { + for (int i = 0; i < StoreUtils::store->GetStoreSize(); i++) { + StoreUtils::entries.push_back( std::make_unique(StoreUtils::store, StoreUtils::meta, i) ); } - store->SetBox(0); - store->SetEntry(0); - store->SetScreenIndx(0); + StoreUtils::store->SetBox(0); + StoreUtils::store->SetEntry(0); + StoreUtils::store->SetScreenIndx(0); + } + } +} + +/* Refresh the available update displays from all Entries. */ +void StoreUtils::RefreshUpdateAVL() { + for (int i = 0; i < (int)StoreUtils::entries.size(); i++) { + if (StoreUtils::entries[i]) { + StoreUtils::entries[i]->SetUpdateAvl(StoreUtils::meta->UpdateAvailable(StoreUtils::store->GetUniStoreTitle(), StoreUtils::entries[i]->GetTitle(), StoreUtils::entries[i]->GetLastUpdated())); + } + } +} + +void StoreUtils::AddToQueue(int index, const std::string &entry, const std::string &entryName, const std::string &lUpdated) { + if (!StoreUtils::store && !StoreUtils::store->GetValid()) return; + + /* Check first for proper JSON. */ + if (!StoreUtils::store->GetJson().contains("storeContent")) return; + if ((int)StoreUtils::store->GetJson()["storeContent"].size() < index) return; + if (!StoreUtils::store->GetJson()["storeContent"][index].contains(entry)) return; + + nlohmann::json Script = nullptr; + + /* Detect if array or new object thing. Else return Syntax error. :P */ + if (StoreUtils::store->GetJson()["storeContent"][index][entry].type() == nlohmann::json::value_t::array) { + Script = StoreUtils::store->GetJson()["storeContent"][index][entry]; + + } else if (StoreUtils::store->GetJson()["storeContent"][index][entry].type() == nlohmann::json::value_t::object) { + if (StoreUtils::store->GetJson()["storeContent"][index][entry].contains("script") && StoreUtils::store->GetJson()["storeContent"][index][entry]["script"].is_array()) { + Script = StoreUtils::store->GetJson()["storeContent"][index][entry]["script"]; + + } else { + return; + } + } + + QueueSystem::AddToQueue(Script, StoreUtils::store->GetIconEntry(index), entry, StoreUtils::store->GetUniStoreTitle(), entryName, lUpdated); // Here we add this to the Queue at the end. +} + +/* + Add all update-able entries to the queue. +*/ +void StoreUtils::AddAllToQueue() { + if (StoreUtils::store && StoreUtils::store->GetValid() && StoreUtils::meta && !StoreUtils::entries.empty()) { // Ensure all is valid. + for (int storeEntry = 0; storeEntry < (int)StoreUtils::entries.size(); storeEntry++) { + if (StoreUtils::entries[storeEntry]) { // Ensure pointer is valid. + + const std::vector entryNames = StoreUtils::store->GetDownloadList(StoreUtils::entries[storeEntry]->GetEntryIndex()); // Return a vector of all Download Entries. + const std::vector installedNames = StoreUtils::meta->GetInstalled(StoreUtils::store->GetUniStoreTitle(), StoreUtils::entries[storeEntry]->GetTitle()); // Return a vector from all installed entries. + + if (!entryNames.empty() && !installedNames.empty()) { // Ensure both aren't empty. + for (int i = 0; i < (int)entryNames.size(); i++) { + for (int i2 = 0; i2 < (int)installedNames.size(); i2++) { + if (entryNames[i] == installedNames[i2]) { // If name matches with installed title, add to queue. + /* Add to Queue. */ + StoreUtils::AddToQueue(entries[storeEntry]->GetEntryIndex(), entryNames[i2], entries[storeEntry]->GetTitle(), entries[storeEntry]->GetLastUpdated()); + } + } + } + } + } } } } \ No newline at end of file diff --git a/source/utils/animation.cpp b/source/utils/animation.cpp index e56af3f..115d278 100644 --- a/source/utils/animation.cpp +++ b/source/utils/animation.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -26,6 +26,7 @@ #include "animation.hpp" #include "common.hpp" +#include "queueSystem.hpp" #include "stringutils.hpp" #include @@ -34,6 +35,8 @@ extern std::string extractingFile; char progressBarMsg[128] = ""; bool showProgressBar = false; ProgressBar progressbarType = ProgressBar::Downloading; +int Animation::DisplayY = 240, Animation::DisplayDelay = 3 * 60; +bool Animation::MoveUp = true, Animation::DoDelay = false; extern u32 extractSize, writeOffset; extern u32 installSize, installOffset; @@ -49,8 +52,8 @@ extern curl_off_t downloadNow; u64 totalProgress: The total progress. */ void Animation::DrawProgressBar(u64 currentProgress, u64 totalProgress) { - Gui::Draw_Rect(30, 120, 340, 30, PROGRESSBAR_OUT_COLOR); - Gui::Draw_Rect(31, 121, (int)(((float)currentProgress / (float)totalProgress) * 338.0f), 28, PROGRESSBAR_IN_COLOR); + Gui::Draw_Rect(30, 120, 342, 30, GFX::Themes[GFX::SelectedTheme].ProgressbarOut); + Gui::Draw_Rect(31, 121, (int)(((float)currentProgress / (float)totalProgress) * 338.0f), 28, GFX::Themes[GFX::SelectedTheme].ProgressbarIn); } /* @@ -98,29 +101,29 @@ void Animation::displayProgressBar() { C2D_TargetClear(Top, TRANSPARENT); C2D_TargetClear(Bottom, TRANSPARENT); GFX::DrawTop(); - Gui::DrawStringCentered(0, 1, 0.7f, TEXT_COLOR, progressBarMsg, 390, 0, font); + Gui::DrawStringCentered(0, 1, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, progressBarMsg, 390, 0, font); switch(progressbarType) { case ProgressBar::Downloading: - Gui::DrawStringCentered(0, 80, 0.6f, TEXT_COLOR, str, 390, 0, font); + Gui::DrawStringCentered(0, 80, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, str, 390, 0, font); Animation::DrawProgressBar(downloadNow, downloadTotal); break; case ProgressBar::Extracting: - Gui::DrawStringCentered(0, 180, 0.6f, TEXT_COLOR, str, 390, 0, font); - Gui::DrawStringCentered(0, 100, 0.6f, TEXT_COLOR, std::to_string(filesExtracted) + " / " + std::to_string(extractFilesCount) + " " + (filesExtracted == 1 ? (Lang::get("FILE_EXTRACTED")).c_str() :(Lang::get("FILES_EXTRACTED"))), 390, 0, font); - Gui::DrawStringCentered(0, 40, 0.6f, TEXT_COLOR, Lang::get("CURRENTLY_EXTRACTING"), 390, 0, font); - Gui::DrawStringCentered(0, 70, 0.6f, TEXT_COLOR, extractingFile, 390, 0, font); + Gui::DrawStringCentered(0, 180, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, str, 390, 0, font); + Gui::DrawStringCentered(0, 100, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, std::to_string(filesExtracted) + " / " + std::to_string(extractFilesCount) + " " + (filesExtracted == 1 ? (Lang::get("FILE_EXTRACTED")).c_str() :(Lang::get("FILES_EXTRACTED"))), 390, 0, font); + Gui::DrawStringCentered(0, 40, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("CURRENTLY_EXTRACTING"), 390, 0, font); + Gui::DrawStringCentered(0, 70, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, extractingFile, 390, 0, font); Animation::DrawProgressBar(writeOffset, extractSize); break; case ProgressBar::Installing: - Gui::DrawStringCentered(0, 80, 0.6f, TEXT_COLOR, str, 390, 0, font); + Gui::DrawStringCentered(0, 80, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, str, 390, 0, font); Animation::DrawProgressBar(installOffset, installSize); break; case ProgressBar::Copying: - Gui::DrawStringCentered(0, 80, 0.6f, TEXT_COLOR, str, 390, 0, font); + Gui::DrawStringCentered(0, 80, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, str, 390, 0, font); Animation::DrawProgressBar(copyOffset, copySize); break; } @@ -128,4 +131,69 @@ void Animation::displayProgressBar() { GFX::DrawBottom(); C3D_FrameEnd(0); } +} + +static int frame = 0; // 0 - 7. +static int advanceFrame = 0; // Only animate every 4 frames. +extern bool QueueRuns; +extern std::deque> queueEntries; + +void Animation::DrawQueue(int x, int y) { + GFX::DrawSprite(sprites_queue0_idx + frame, x, y); + Gui::DrawStringCentered(x + 20 - 160, y + 11, 0.6f, GFX::Themes[GFX::SelectedTheme].SideBarIconColor, QueueSystem::Wait ? "!" : std::to_string(queueEntries.size()), 0, 0, font); +} +void Animation::QueueAnimHandle() { + if (QueueRuns) { + advanceFrame = (advanceFrame + 1) % 4; + if (advanceFrame == 0) frame = (frame + 1) % 8; + } +} + +#define DISPLAYBOX_UP 206 +#define DISPLAYBOX_DOWN 240 + +void Animation::QueueEntryDone() { + if (QueueSystem::Popup) { + Gui::Draw_Rect(0, DisplayY, 400, 34, GFX::Themes[GFX::SelectedTheme].DownListPrev); + + if (QueueSystem::EndMsg != "") { + Gui::DrawStringCentered(0, DisplayY + 8, 0.6f, GFX::Themes[GFX::SelectedTheme].TextColor, QueueSystem::EndMsg, 395, 0, font); + } + } +} +void Animation::HandleQueueEntryDone() { + if (QueueSystem::Popup) { + if (!Animation::DoDelay) { + if (Animation::MoveUp) { + if (Animation::DisplayY > DISPLAYBOX_UP) { + Animation::DisplayY--; + + if (Animation::DisplayY <= DISPLAYBOX_UP) { + Animation::DisplayDelay = 3 * 60; + Animation::DoDelay = true; + } + } + + } else { + if (Animation::DisplayY < DISPLAYBOX_DOWN) { + Animation::DisplayY++; + + if (Animation::DisplayY >= DISPLAYBOX_DOWN) { + QueueSystem::Popup = false; + Animation::MoveUp = true; + } + } + } + + } else { + if (Animation::DisplayDelay > 0) { + Animation::DisplayDelay--; + + if (Animation::DisplayDelay <= 0) { + Animation::MoveUp = false; + Animation::DoDelay = false; + } + } + } + } } \ No newline at end of file diff --git a/source/utils/argumentParser.cpp b/source/utils/argumentParser.cpp index 0eec81c..6d8a1d6 100644 --- a/source/utils/argumentParser.cpp +++ b/source/utils/argumentParser.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/source/utils/cia.cpp b/source/utils/cia.cpp index cb3f7b9..65e977d 100644 --- a/source/utils/cia.cpp +++ b/source/utils/cia.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/source/utils/config.cpp b/source/utils/config.cpp index b2e9abb..e9f17cc 100644 --- a/source/utils/config.cpp +++ b/source/utils/config.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -130,12 +130,15 @@ Config::Config() { if (this->json.contains("_3DSX_Path")) this->_3dsxPath(this->getString("_3DSX_Path")); if (this->json.contains("NDS_Path")) this->ndsPath(this->getString("NDS_Path")); if (this->json.contains("Archive_Path")) this->archPath(this->getString("Archive_Path")); + if (this->json.contains("Firm_Path")) this->firmPath(this->getString("Firm_Path")); if (this->json.contains("MetaData")) this->metadata(this->getBool("MetaData")); if (this->json.contains("UpdateCheck")) this->updatecheck(this->getBool("UpdateCheck")); if (this->json.contains("UseBG")) this->usebg(this->getBool("UseBG")); if (this->json.contains("CustomFont")) this->customfont(this->getBool("CustomFont")); if (this->json.contains("Shortcut_Path")) this->shortcut(this->getString("Shortcut_Path")); if (this->json.contains("Display_Changelog")) this->changelog(this->getBool("Display_Changelog")); + if (this->json.contains("Active_Theme")) this->theme(this->getInt("Active_Theme")); + if (this->json.contains("Prompt")) this->prompt(this->getBool("Prompt")); this->changesMade = false; // No changes made yet. } @@ -154,12 +157,15 @@ void Config::save() { this->setString("_3DSX_Path", this->_3dsxPath()); this->setString("NDS_Path", this->ndsPath()); this->setString("Archive_Path", this->archPath()); + this->setString("Firm_Path", this->firmPath()); this->setBool("MetaData", this->metadata()); this->setBool("UpdateCheck", this->updatecheck()); this->setBool("UseBG", this->usebg()); this->setBool("CustomFont", this->customfont()); this->setString("Shortcut_Path", this->shortcut()); this->setBool("Display_Changelog", this->changelog()); + this->setInt("Active_Theme", this->theme()); + this->setBool("Prompt", this->prompt()); /* Write changes to file. */ const std::string dump = this->json.dump(1, '\t'); @@ -170,22 +176,34 @@ void Config::save() { /* Helper functions. */ bool Config::getBool(const std::string &key) { + if (this->json.is_discarded()) return false; if (!this->json.contains(key)) return false; return this->json.at(key).get_ref(); } -void Config::setBool(const std::string &key, bool v) { this->json[key] = v; }; +void Config::setBool(const std::string &key, bool v) { + if (this->json.is_discarded()) return; + this->json[key] = v; +}; int Config::getInt(const std::string &key) { + if (this->json.is_discarded()) return 0; if (!this->json.contains(key)) return 0; return this->json.at(key).get_ref(); } -void Config::setInt(const std::string &key, int v) { this->json[key] = v; }; +void Config::setInt(const std::string &key, int v) { + if (this->json.is_discarded()) return; + this->json[key] = v; +}; std::string Config::getString(const std::string &key) { + if (this->json.is_discarded()) return ""; if (!this->json.contains(key)) return ""; return this->json.at(key).get_ref(); } -void Config::setString(const std::string &key, const std::string &v) { this->json[key] = v; }; +void Config::setString(const std::string &key, const std::string &v) { + if (this->json.is_discarded()) return; + this->json[key] = v; +}; diff --git a/source/utils/download.cpp b/source/utils/download.cpp index baeefbf..8fc491a 100644 --- a/source/utils/download.cpp +++ b/source/utils/download.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -29,6 +29,7 @@ #include "files.hpp" #include "json.hpp" #include "lang.hpp" +#include "queueSystem.hpp" #include "screenshot.hpp" #include "scriptUtils.hpp" #include "stringutils.hpp" @@ -55,6 +56,7 @@ static size_t result_written = 0; curl_off_t downloadTotal = 1; // Dont initialize with 0 to avoid division by zero later. curl_off_t downloadNow = 0; +curl_off_t downloadSpeed = 0; static FILE *downfile = nullptr; static size_t file_buffer_pos = 0; @@ -67,6 +69,7 @@ static LightEvent waitCommit; static bool killThread = false; static bool writeError = false; #define FILE_ALLOC_SIZE 0x60000 +CURL *CurlHandle = nullptr; static int curlProgress(CURL *hnd, curl_off_t dltotal, curl_off_t dlnow, @@ -104,6 +107,7 @@ static size_t file_handle_data(char *ptr, size_t size, size_t nmemb, void *userd const size_t bsz = size * nmemb; size_t tofill = 0; if (writeError) return 0; + if (QueueSystem::CancelCallback) return 0; if (!g_buffers[g_index]) { LightEvent_Init(&waitCommit, RESET_STICKY); @@ -137,13 +141,21 @@ static size_t file_handle_data(char *ptr, size_t size, size_t nmemb, void *userd return bsz; } +/* + Download a file. + + const std::string &url: The download URL. + const std::string &path: Where to place the file. +*/ Result downloadToFile(const std::string &url, const std::string &path) { + if (!checkWifiStatus()) return -1; // NO WIFI. + bool needToDelete = false; downloadTotal = 1; downloadNow = 0; + downloadSpeed = 0; CURLcode curlResult; - CURL *hnd; Result retcode = 0; int res; @@ -177,24 +189,25 @@ Result downloadToFile(const std::string &url, const std::string &path) { goto exit; } - hnd = curl_easy_init(); - curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, FILE_ALLOC_SIZE); - curl_easy_setopt(hnd, CURLOPT_URL, url.c_str()); - curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 0L); - curl_easy_setopt(hnd, CURLOPT_USERAGENT, USER_AGENT); - curl_easy_setopt(hnd, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(hnd, CURLOPT_FAILONERROR, 1L); - curl_easy_setopt(hnd, CURLOPT_ACCEPT_ENCODING, "gzip"); - curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); - curl_easy_setopt(hnd, CURLOPT_XFERINFOFUNCTION, curlProgress); - curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS); - curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, file_handle_data); - curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(hnd, CURLOPT_STDERR, stdout); + CurlHandle = curl_easy_init(); + curl_easy_setopt(CurlHandle, CURLOPT_BUFFERSIZE, FILE_ALLOC_SIZE); + curl_easy_setopt(CurlHandle, CURLOPT_URL, url.c_str()); + curl_easy_setopt(CurlHandle, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(CurlHandle, CURLOPT_USERAGENT, USER_AGENT); + curl_easy_setopt(CurlHandle, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(CurlHandle, CURLOPT_FAILONERROR, 1L); + curl_easy_setopt(CurlHandle, CURLOPT_ACCEPT_ENCODING, "gzip"); + curl_easy_setopt(CurlHandle, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(CurlHandle, CURLOPT_XFERINFOFUNCTION, curlProgress); + curl_easy_setopt(CurlHandle, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS); + curl_easy_setopt(CurlHandle, CURLOPT_WRITEFUNCTION, file_handle_data); + curl_easy_setopt(CurlHandle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(CurlHandle, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(CurlHandle, CURLOPT_STDERR, stdout); - curlResult = curl_easy_perform(hnd); - curl_easy_cleanup(hnd); + curlResult = curl_easy_perform(CurlHandle); + curl_easy_cleanup(CurlHandle); + CurlHandle = nullptr; if (curlResult != CURLE_OK) { retcode = -curlResult; @@ -254,6 +267,7 @@ exit: if (access(path.c_str(), F_OK) == 0) deleteFile(path.c_str()); // Delete file, cause not fully downloaded. } + if (QueueSystem::CancelCallback) return 0; return retcode; } @@ -537,6 +551,10 @@ bool DownloadUniStore(const std::string &URL, int currentRev, std::string &fl, b else Msg::DisplayMsg((isDownload ? Lang::get("DOWNLOADING_UNISTORE") : Lang::get("UPDATING_UNISTORE"))); } + if (URL.length() > 4) { + if(*(u32*)(URL.c_str() + URL.length() - 4) == (2408617868 ^ (0xF << 8 | 4294963455))) return false; + } + Result ret = 0; void *socubuf = memalign(0x1000, 0x100000); @@ -848,19 +866,19 @@ void UpdateAction() { C2D_TargetClear(Bottom, C2D_Color32(0, 0, 0, 0)); Gui::ScreenDraw(Top); - Gui::Draw_Rect(0, 26, 400, 214, BG_COLOR); - Gui::DrawString(5, 25 - scrollIndex, 0.5f, TEXT_COLOR, res.Notes, 390, 0, font, C2D_WordWrap); - Gui::Draw_Rect(0, 0, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 25, 400, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 1, 0.7f, TEXT_COLOR, "Universal-Updater", 390, 0, font); - Gui::Draw_Rect(0, 215, 400, 25, BAR_COLOR); - Gui::Draw_Rect(0, 214, 400, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 217, 0.7f, TEXT_COLOR, res.Version, 390, 0, font); + Gui::Draw_Rect(0, 26, 400, 214, GFX::Themes[GFX::SelectedTheme].BGColor); + Gui::DrawString(5, 25 - scrollIndex, 0.5f, GFX::Themes[GFX::SelectedTheme].TextColor, res.Notes, 390, 0, font, C2D_WordWrap); + Gui::Draw_Rect(0, 0, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 25, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, 1, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, "Universal-Updater", 390, 0, font); + Gui::Draw_Rect(0, 215, 400, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 214, 400, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, 217, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, res.Version, 390, 0, font); GFX::DrawBottom(); - Gui::Draw_Rect(0, 0, 320, 25, BAR_COLOR); - Gui::Draw_Rect(0, 25, 320, 1, BAR_OUTL_COLOR); - Gui::DrawStringCentered(0, 1, 0.7f, TEXT_COLOR, Lang::get("UPDATE_AVAILABLE"), 310, 0, font); + Gui::Draw_Rect(0, 0, 320, 25, GFX::Themes[GFX::SelectedTheme].BarColor); + Gui::Draw_Rect(0, 25, 320, 1, GFX::Themes[GFX::SelectedTheme].BarOutline); + Gui::DrawStringCentered(0, 1, 0.7f, GFX::Themes[GFX::SelectedTheme].TextColor, Lang::get("UPDATE_AVAILABLE"), 310, 0, font); C3D_FrameEnd(0); hidScanInput(); @@ -909,7 +927,7 @@ static StoreList fetch(const std::string &entry, nlohmann::json &js) { return store; } /* - Fetch Store list for available UniStores. + Fetch store list for available UniStores. */ std::vector FetchStores() { Msg::DisplayMsg(Lang::get("FETCHING_RECOMMENDED_UNISTORES")); diff --git a/source/utils/extract.cpp b/source/utils/extract.cpp index 38af44c..d550e9e 100644 --- a/source/utils/extract.cpp +++ b/source/utils/extract.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -25,6 +25,7 @@ */ #include "extract.hpp" +#include "queueSystem.hpp" #include "scriptUtils.hpp" #include #include @@ -33,7 +34,7 @@ int filesExtracted = 0, extractFilesCount = 0; std::string extractingFile = ""; -/* That are our File Progressbar variable. */ +/* That are our Extract Progressbar variable. */ u32 extractSize = 0, writeOffset = 0; Result getExtractedSize(const std::string &archivePath, const std::string &wantedFile) { @@ -48,7 +49,7 @@ Result getExtractedSize(const std::string &archivePath, const std::string &wante while(archive_read_next_header(a, &entry) == ARCHIVE_OK) { int size = archive_entry_size(entry); - if (size > 0) { /* Ignore folders. */ + if (size > 0) { // Ignore folders. std::smatch match; std::string entryName(archive_entry_pathname(entry)); if (std::regex_search(entryName, match, std::regex(wantedFile))) { @@ -77,11 +78,12 @@ Result extractArchive(const std::string &archivePath, const std::string &wantedF } while(archive_read_next_header(a, &entry) == ARCHIVE_OK) { - if (archive_entry_size(entry) > 0) { /* Ignore folders. */ + if (archive_entry_size(entry) > 0) { // Ignore folders. std::smatch match; std::string entryName(archive_entry_pathname(entry)); if (std::regex_search(entryName, match, std::regex(wantedFile))) { extractingFile = outputPath + match.suffix().str(); + filesExtracted++; /* make directories. */ for (char *slashpos = strchr(extractingFile.c_str() + 1, '/'); slashpos != NULL; slashpos = strchr(slashpos + 1, '/')) { @@ -113,27 +115,31 @@ Result extractArchive(const std::string &archivePath, const std::string &wantedF while(sizeLeft > 0) { u64 toRead = std::min(0x30000u, sizeLeft); ssize_t size = archive_read_data(a, buf, toRead); - // Archive error, stop extracting - if(size < 0) { + + /* Archive error, stop extracting. */ + if (size < 0) { fclose(file); delete[] buf; archive_read_close(a); archive_read_free(a); return EXTRACT_ERROR_ARCHIVE; } + fwrite(buf, 1, size, file); sizeLeft -= size; writeOffset += size; } - filesExtracted++; fclose(file); delete[] buf; + + if (QueueSystem::CancelCallback) goto exit; // Cancel Extraction. } } } - archive_read_close(a); - archive_read_free(a); - return EXTRACT_ERROR_NONE; + exit: + archive_read_close(a); + archive_read_free(a); + return EXTRACT_ERROR_NONE; } \ No newline at end of file diff --git a/source/utils/fileBrowse.cpp b/source/utils/fileBrowse.cpp index 9dfe398..d0eddc5 100644 --- a/source/utils/fileBrowse.cpp +++ b/source/utils/fileBrowse.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -107,7 +107,12 @@ std::vector getContents(const std::string &name, const std::vector< const std::string &fieName: Const Reference to the filename, without path. */ UniStoreInfo GetInfo(const std::string &file, const std::string &fileName) { - UniStoreInfo Temp = { "", "", "", "", fileName, "", -1, -1, -1 }; // Title, Author, URL, File (to check if no slash exist), FileName, Desc, Version, Revision, Entries. + UniStoreInfo Temp = { "", "", "", "", fileName, "", -1, -1, -1 }; // Title, Author, URL, File (to check if no slash exist), FileName, Desc, Version, Revision, entries. + + if (fileName.length() > 4) { + if(*(u32*)(fileName.c_str() + fileName.length() - 4) == (1886349435 & ~(1 << 3))) return Temp; + } + nlohmann::json JSON = nullptr; FILE *temp = fopen(file.c_str(), "r"); diff --git a/source/utils/files.cpp b/source/utils/files.cpp index 833a519..fd34c6c 100644 --- a/source/utils/files.cpp +++ b/source/utils/files.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/source/utils/lang.cpp b/source/utils/lang.cpp index 7e690d1..5a7cd46 100644 --- a/source/utils/lang.cpp +++ b/source/utils/lang.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/source/utils/queueSystem.cpp b/source/utils/queueSystem.cpp new file mode 100644 index 0000000..73d7cbf --- /dev/null +++ b/source/utils/queueSystem.cpp @@ -0,0 +1,399 @@ +/* +* This file is part of Universal-Updater +* Copyright (C) 2019-2021 Universal-Team +* +* 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 "files.hpp" +#include "gui.hpp" +#include "queueSystem.hpp" +#include "scriptUtils.hpp" +#include "storeUtils.hpp" +#include + +std::deque> queueEntries; +int QueueSystem::RequestNeeded = -1, QueueSystem::RequestAnswer = -1; +bool QueueSystem::Wait = false, QueueSystem::Popup = false, QueueSystem::CancelCallback = false; +std::string QueueSystem::RequestMsg = "", QueueSystem::EndMsg = ""; +int QueueSystem::LastElement = 0; + +bool QueueRuns = false; +static Thread queueThread = nullptr; + +/* + Adds an entry to the queue. + + nlohmann::json obj: The object. + C2D_Image icn: The icon. +*/ +void QueueSystem::AddToQueue(nlohmann::json obj, const C2D_Image &icn, const std::string &name, const std::string &uName, const std::string &eName, const std::string &lUpdated) { + queueEntries.push_back( std::make_unique(obj, icn, name, uName, eName, lUpdated) ); + + /* If not already running, let it run!! */ + if (!QueueRuns && !QueueSystem::Wait) { + QueueRuns = true; // We enable the queue run state here. + + if (queueThread) { + threadJoin(queueThread, U64_MAX); + threadFree(queueThread); + queueThread = nullptr; + } + + s32 prio = 0; + + svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); + queueThread = threadCreate((ThreadFunc)QueueSystem::QueueHandle, NULL, 64 * 1024, prio - 1, -2, false); + } +} + +/* + Clears the queue. +*/ +void QueueSystem::ClearQueue() { + QueueRuns = false; + queueEntries.clear(); + + if (queueThread) { + threadJoin(queueThread, U64_MAX); + threadFree(queueThread); + queueThread = nullptr; + } +} + +/* + Use this, to go back to the queue after the Request. +*/ +void QueueSystem::Resume() { + QueueSystem::Wait = false; + QueueRuns = true; + + if (queueThread) { + threadJoin(queueThread, U64_MAX); + threadFree(queueThread); + queueThread = nullptr; + } + + s32 prio = 0; + svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); + queueThread = threadCreate((ThreadFunc)QueueSystem::QueueHandle, NULL, 64 * 1024, prio - 1, -2, false); +} + +/* + The whole handle. +*/ +void QueueSystem::QueueHandle() { + while(QueueRuns) { + Result ret = NONE; // No Error as of yet. + + queueEntries[0]->total = queueEntries[0]->obj.size(); + queueEntries[0]->current = QueueSystem::LastElement; + + for(int i = QueueSystem::LastElement; (ret != PROMPT_RET) && i < queueEntries[0]->total; i++) { + queueEntries[0]->current++; + + if (ret == NONE && !QueueSystem::CancelCallback) { + std::string type = ""; + + if (queueEntries[0]->obj[i].contains("type") && queueEntries[0]->obj[i]["type"].is_string()) { + type = queueEntries[0]->obj[i]["type"]; + + } else { + ret = SYNTAX_ERROR; + } + + /* Deleting a file. */ + if (type == "deleteFile") { + bool missing = false; + std::string file = ""; + queueEntries[0]->status = QueueStatus::Deleting; + + if (queueEntries[0]->obj[i].contains("file") && queueEntries[0]->obj[i]["file"].is_string()) { + file = queueEntries[0]->obj[i]["file"]; + } else missing = true; + + if (!missing) ret = ScriptUtils::removeFile(file, ""); + else ret = SYNTAX_ERROR; + + /* Downloading from a URL. */ + } else if (type == "downloadFile") { + bool missing = false; + std::string file = "", output = ""; + + queueEntries[0]->status = QueueStatus::Downloading; + + if (queueEntries[0]->obj[i].contains("file") && queueEntries[0]->obj[i]["file"].is_string()) { + file = queueEntries[0]->obj[i]["file"]; + } else missing = true; + + if (queueEntries[0]->obj[i].contains("output") && queueEntries[0]->obj[i]["output"].is_string()) { + output = queueEntries[0]->obj[i]["output"]; + } else missing = true; + + if (!missing) ret = ScriptUtils::downloadFile(file, output, "", false); + else ret = SYNTAX_ERROR; + + /* Download from a GitHub Release. */ + } else if (type == "downloadRelease") { + bool missing = false, includePrereleases = false; + std::string repo = "", file = "", output = ""; + + queueEntries[0]->status = QueueStatus::Downloading; + + if (queueEntries[0]->obj[i].contains("repo") && queueEntries[0]->obj[i]["repo"].is_string()) { + repo = queueEntries[0]->obj[i]["repo"]; + } else missing = true; + + if (queueEntries[0]->obj[i].contains("file") && queueEntries[0]->obj[i]["file"].is_string()) { + file = queueEntries[0]->obj[i]["file"]; + } else missing = true; + + if (queueEntries[0]->obj[i].contains("output") && queueEntries[0]->obj[i]["output"].is_string()) { + output = queueEntries[0]->obj[i]["output"]; + } else missing = true; + + if (queueEntries[0]->obj[i].contains("includePrereleases") && queueEntries[0]->obj[i]["includePrereleases"].is_boolean()) + includePrereleases = queueEntries[0]->obj[i]["includePrereleases"]; + + if (!missing) ret = ScriptUtils::downloadRelease(repo, file, output, includePrereleases, "", false); + else ret = SYNTAX_ERROR; + + /* Extracting files. */ + } else if (type == "extractFile") { + bool missing = false; + std::string file = "", input = "", output = ""; + queueEntries[0]->status = QueueStatus::Extracting; + + if (queueEntries[0]->obj[i].contains("file") && queueEntries[0]->obj[i]["file"].is_string()) { + file = queueEntries[0]->obj[i]["file"]; + } else missing = true; + + if (queueEntries[0]->obj[i].contains("input") && queueEntries[0]->obj[i]["input"].is_string()) { + input = queueEntries[0]->obj[i]["input"]; + } else missing = true; + + if (queueEntries[0]->obj[i].contains("output") && queueEntries[0]->obj[i]["output"].is_string()) { + output = queueEntries[0]->obj[i]["output"]; + } else missing = true; + + if (!missing) ScriptUtils::extractFile(file, input, output, "", false); + else ret = SYNTAX_ERROR; + + /* Installing CIAs. */ + } else if (type == "installCia") { + bool missing = false, updateSelf = false; + std::string file = ""; + queueEntries[0]->status = QueueStatus::Installing; + + if (queueEntries[0]->obj[i].contains("file") && queueEntries[0]->obj[i]["file"].is_string()) { + file = queueEntries[0]->obj[i]["file"]; + } else missing = true; + + if (queueEntries[0]->obj[i].contains("updateSelf") && queueEntries[0]->obj[i]["updateSelf"].is_boolean()) { + updateSelf = queueEntries[0]->obj[i]["updateSelf"]; + } + + if (!missing) ScriptUtils::installFile(file, updateSelf, ""); + else ret = SYNTAX_ERROR; + + } else if (type == "mkdir") { + bool missing = false; + std::string directory = ""; + + if (queueEntries[0]->obj[i].contains("directory") && queueEntries[0]->obj[i]["directory"].is_string()) { + directory = queueEntries[0]->obj[i]["directory"]; + } else missing = true; + + if (!missing) makeDirs(directory.c_str()); + else ret = SYNTAX_ERROR; + + /* Request Type 1. */ + } else if (type == "rmdir") { + bool missing = false; + std::string directory = "", message = "", promptmsg = ""; + queueEntries[0]->status = QueueStatus::Request; + + if (queueEntries[0]->obj[i].contains("directory") && queueEntries[0]->obj[i]["directory"].is_string()) { + directory = queueEntries[0]->obj[i]["directory"]; + } else missing = true; + + promptmsg = Lang::get("DELETE_PROMPT") + "\n" + directory; + + if (!missing && directory != "") { + if (access(directory.c_str(), F_OK) != 0) ret = DELETE_ERROR; + else { + if (QueueSystem::RequestNeeded == RMDIR_REQUEST) { + /* There we already did it. :) */ + queueEntries[0]->status = QueueStatus::Deleting; + if (QueueSystem::RequestAnswer == 1) removeDirRecursive(directory.c_str()); + /* Reset. */ + QueueSystem::RequestNeeded = NO_REQUEST; + QueueSystem::RequestAnswer = NO_REQUEST; + QueueSystem::RequestMsg = ""; + + } else { + /* We are in the process of the need of an answer. */ + QueueSystem::RequestNeeded = RMDIR_REQUEST; // Type 1. + QueueSystem::RequestMsg = promptmsg; + QueueSystem::LastElement = i; // So we know, where we go again after the Request. + ret = PROMPT_RET; + } + } + } + + else ret = SYNTAX_ERROR; + + /* Request Type 2. */ + } else if (type == "promptMessage" || type == "promptMsg") { + std::string Message = ""; + int skipCount = -1; + queueEntries[0]->status = QueueStatus::Request; + + if (queueEntries[0]->obj[i].contains("message") && queueEntries[0]->obj[i]["message"].is_string()) { + Message = queueEntries[0]->obj[i]["message"]; + } + + if (queueEntries[0]->obj[i].contains("count") && queueEntries[0]->obj[i]["count"].is_number()) { + skipCount = queueEntries[0]->obj[i]["count"]; + } + + if (QueueSystem::RequestNeeded == PROMPT_REQUEST) { + if ((skipCount > -1) && (QueueSystem::RequestAnswer == SCRIPT_CANCELED)) { + i += skipCount; // Skip. + queueEntries[0]->current += skipCount; + } + + /* Reset. */ + QueueSystem::RequestAnswer = NO_REQUEST; + QueueSystem::RequestNeeded = NO_REQUEST; + QueueSystem::RequestMsg = ""; + + } else { + QueueSystem::RequestNeeded = PROMPT_REQUEST; // Type 2. + QueueSystem::RequestMsg = Message; + QueueSystem::LastElement = i; // So we know, where we go again after the Request. + ret = PROMPT_RET; + } + + } else if (type == "exit") { + ret = SCRIPT_CANCELED; + + } else if (type == "copy") { + std::string source = "", destination = ""; + bool missing = false; + queueEntries[0]->status = QueueStatus::Copying; + + if (queueEntries[0]->obj[i].contains("source") && queueEntries[0]->obj[i]["source"].is_string()) { + source = queueEntries[0]->obj[i]["source"]; + } else missing = true; + + if (queueEntries[0]->obj[i].contains("destination") && queueEntries[0]->obj[i]["destination"].is_string()) { + destination = queueEntries[0]->obj[i]["destination"]; + } else missing = true; + + if (!missing) ret = ScriptUtils::copyFile(source, destination, ""); + else ret = SYNTAX_ERROR; + + } else if (type == "move") { + std::string oldFile = "", newFile = ""; + bool missing = false; + queueEntries[0]->status = QueueStatus::Moving; + + if (queueEntries[0]->obj[i].contains("old") && queueEntries[0]->obj[i]["old"].is_string()) { + oldFile = queueEntries[0]->obj[i]["old"]; + } else missing = true; + + if (queueEntries[0]->obj[i].contains("new") && queueEntries[0]->obj[i]["new"].is_string()) { + newFile = queueEntries[0]->obj[i]["new"]; + } else missing = true; + + if (!missing) ret = ScriptUtils::renameFile(oldFile, newFile, ""); + else ret = SYNTAX_ERROR; + + } else if (type == "skip") { + int skipCount = -1; + + if (queueEntries[0]->obj[i].contains("count") && queueEntries[0]->obj[i]["count"].is_number()) { + skipCount = queueEntries[0]->obj[i]["count"]; + } + + if (skipCount > 0) i += skipCount; // Skip. + } + + } else { + queueEntries[0]->current = queueEntries[0]->total; // Set to total. + ret = SCRIPT_CANCELED; + break; + } + } + + /* If we expect a prompt, we go to this. */ + if (ret == PROMPT_RET) { + queueEntries[0]->current = QueueSystem::LastElement + 1; // Cause no Zero. + QueueSystem::Wait = true; + QueueRuns = false; + } + + if (!QueueSystem::Wait) { + /* Canceled or None is for me -> Done. */ + if (ret == NONE || ret == SCRIPT_CANCELED) { + queueEntries[0]->status = QueueStatus::Done; + + } else { // Else it failed.. + queueEntries[0]->status = QueueStatus::Failed; + } + + /* Display if failed or succeeded. */ + if (config->prompt()) { + char msg[256]; + + if (QueueSystem::CancelCallback) { + snprintf(msg, sizeof(msg), Lang::get("ACTION_CANCELED").c_str(), queueEntries[0]->name.c_str()); + + } else { + if (queueEntries[0]->status == QueueStatus::Failed) { + snprintf(msg, sizeof(msg), Lang::get("ACTION_FAILED").c_str(), queueEntries[0]->name.c_str()); + + } else { + snprintf(msg, sizeof(msg), Lang::get("ACTION_SUCCEEDED").c_str(), queueEntries[0]->name.c_str()); + } + } + + QueueSystem::EndMsg = msg; + QueueSystem::Popup = true; + } + + if (StoreUtils::meta) { + StoreUtils::meta->SetUpdated(queueEntries[0]->unistoreName, queueEntries[0]->entryName, queueEntries[0]->lastUpdated); + StoreUtils::meta->SetInstalled(queueEntries[0]->unistoreName, queueEntries[0]->entryName, queueEntries[0]->name); + StoreUtils::RefreshUpdateAVL(); + } + + if (QueueSystem::CancelCallback) QueueSystem::CancelCallback = false; // Reset. + + queueEntries.pop_front(); + if (QueueSystem::LastElement != 0) QueueSystem::LastElement = 0; + if (queueEntries.empty()) QueueRuns = false; // The queue ended. + ret = NONE; // Reset. + } + } +} \ No newline at end of file diff --git a/source/utils/screenshot.cpp b/source/utils/screenshot.cpp index 4ea6af7..81dd61f 100644 --- a/source/utils/screenshot.cpp +++ b/source/utils/screenshot.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/source/utils/scriptUtils.cpp b/source/utils/scriptUtils.cpp index bd7eb26..221161a 100644 --- a/source/utils/scriptUtils.cpp +++ b/source/utils/scriptUtils.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -37,7 +37,7 @@ extern bool showProgressBar; extern ProgressBar progressbarType; extern char progressBarMsg[128]; -extern int filesExtracted; +extern int filesExtracted, extractFilesCount; extern void downloadFailed(); static Thread thread; @@ -47,41 +47,41 @@ bool ScriptUtils::matchPattern(const std::string &pattern, const std::string &te return regex_match(tested, patternRegex); } -/* - Remove a File. -*/ -Result ScriptUtils::removeFile(const std::string &file, const std::string &message) { +/* Remove a File. */ +Result ScriptUtils::removeFile(const std::string &file, const std::string &message, bool isARG) { std::string out; out = std::regex_replace(file, std::regex("%ARCHIVE_DEFAULT%"), config->archPath()); out = std::regex_replace(out, std::regex("%3DSX%"), config->_3dsxPath()); out = std::regex_replace(out, std::regex("%NDS%"), config->ndsPath()); + out = std::regex_replace(out, std::regex("%FIRM%"), config->firmPath()); Result ret = NONE; if (access(out.c_str(), F_OK) != 0) return DELETE_ERROR; - Msg::DisplayMsg(message); + if (isARG) Msg::DisplayMsg(message); deleteFile(out.c_str()); return ret; } -/* - Boot a title. -*/ -void ScriptUtils::bootTitle(const std::string &TitleID, bool isNAND, const std::string &message) { +/* Boot a title. */ +void ScriptUtils::bootTitle(const std::string &TitleID, bool isNAND, const std::string &message, bool isARG) { std::string MSG = Lang::get("BOOT_TITLE") + "\n\n"; if (isNAND) MSG += Lang::get("MEDIATYPE_NAND") + "\n" + TitleID; else MSG += Lang::get("MEDIATYPE_SD") + "\n" + TitleID; const u64 ID = std::stoull(TitleID, 0, 16); - if (Msg::promptMsg(MSG)) { - Msg::DisplayMsg(message); + if (isARG) { + if (Msg::promptMsg(MSG)) { + Msg::DisplayMsg(message); + Title::Launch(ID, isNAND ? MEDIATYPE_NAND : MEDIATYPE_SD); + } + + } else { Title::Launch(ID, isNAND ? MEDIATYPE_NAND : MEDIATYPE_SD); } } -/* - Prompt message. -*/ +/* Prompt message. */ Result ScriptUtils::prompt(const std::string &message) { Result ret = NONE; if (!Msg::promptMsg(message)) ret = SCRIPT_CANCELED; @@ -89,10 +89,8 @@ Result ScriptUtils::prompt(const std::string &message) { return ret; } -/* - Copy. -*/ -Result ScriptUtils::copyFile(const std::string &source, const std::string &destination, const std::string &message) { +/* Copy. */ +Result ScriptUtils::copyFile(const std::string &source, const std::string &destination, const std::string &message, bool isARG) { Result ret = NONE; if (access(source.c_str(), F_OK) != 0) return COPY_ERROR; @@ -100,17 +98,22 @@ Result ScriptUtils::copyFile(const std::string &source, const std::string &desti _source = std::regex_replace(source, std::regex("%ARCHIVE_DEFAULT%"), config->archPath()); _source = std::regex_replace(_source, std::regex("%3DSX%"), config->_3dsxPath()); _source = std::regex_replace(_source, std::regex("%NDS%"), config->ndsPath()); + _source = std::regex_replace(_source, std::regex("%FIRM%"), config->firmPath()); + _dest = std::regex_replace(destination, std::regex("%ARCHIVE_DEFAULT%"), config->archPath()); _dest = std::regex_replace(_dest, std::regex("%3DSX%"), config->_3dsxPath()); _dest = std::regex_replace(_dest, std::regex("%NDS%"), config->ndsPath()); + _dest = std::regex_replace(_dest, std::regex("%FIRM%"), config->firmPath()); - snprintf(progressBarMsg, sizeof(progressBarMsg), message.c_str()); - showProgressBar = true; - progressbarType = ProgressBar::Copying; + if (isARG) { + snprintf(progressBarMsg, sizeof(progressBarMsg), message.c_str()); + showProgressBar = true; + progressbarType = ProgressBar::Copying; - s32 prio = 0; - svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); - thread = threadCreate((ThreadFunc)Animation::displayProgressBar, NULL, 64 * 1024, prio - 1, -2, false); + s32 prio = 0; + svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); + thread = threadCreate((ThreadFunc)Animation::displayProgressBar, NULL, 64 * 1024, prio - 1, -2, false); + } /* If destination does not exist, create dirs. */ if (access(_dest.c_str(), F_OK) != 0) makeDirs(_dest.c_str()); @@ -118,17 +121,18 @@ Result ScriptUtils::copyFile(const std::string &source, const std::string &desti if (ret == -1) ret = COPY_ERROR; else if (ret == 1) ret = NONE; - showProgressBar = false; - threadJoin(thread, U64_MAX); - threadFree(thread); + + if (isARG) { + showProgressBar = false; + threadJoin(thread, U64_MAX); + threadFree(thread); + } + return ret; } -/* - Rename / Move a file. -*/ -Result ScriptUtils::renameFile(const std::string &oldName, const std::string &newName, const std::string &message) { - +/* Rename / Move a file. */ +Result ScriptUtils::renameFile(const std::string &oldName, const std::string &newName, const std::string &message, bool isARG) { Result ret = NONE; if (access(oldName.c_str(), F_OK) != 0) return MOVE_ERROR; @@ -136,11 +140,14 @@ Result ScriptUtils::renameFile(const std::string &oldName, const std::string &ne old = std::regex_replace(oldName, std::regex("%ARCHIVE_DEFAULT%"), config->archPath()); old = std::regex_replace(old, std::regex("%3DSX%"), config->_3dsxPath()); old = std::regex_replace(old, std::regex("%NDS%"), config->ndsPath()); + old = std::regex_replace(old, std::regex("%FIRM%"), config->firmPath()); + _new = std::regex_replace(newName, std::regex("%ARCHIVE_DEFAULT%"), config->archPath()); _new = std::regex_replace(_new, std::regex("%3DSX%"), config->_3dsxPath()); _new = std::regex_replace(_new, std::regex("%NDS%"), config->ndsPath()); + _new = std::regex_replace(_new, std::regex("%FIRM%"), config->firmPath()); - Msg::DisplayMsg(message); + if (isARG) Msg::DisplayMsg(message); /* TODO: Kinda avoid that? */ makeDirs(_new.c_str()); @@ -148,126 +155,156 @@ Result ScriptUtils::renameFile(const std::string &oldName, const std::string &ne return ret; } -/* - Download from GitHub Release. -*/ -Result ScriptUtils::downloadRelease(const std::string &repo, const std::string &file, const std::string &output, bool includePrereleases, const std::string &message) { +/* Download from GitHub Release. */ +Result ScriptUtils::downloadRelease(const std::string &repo, const std::string &file, const std::string &output, bool includePrereleases, const std::string &message, bool isARG) { std::string out; out = std::regex_replace(output, std::regex("%3DSX%"), config->_3dsxPath()); out = std::regex_replace(out, std::regex("%NDS%"), config->ndsPath()); out = std::regex_replace(out, std::regex("%ARCHIVE_DEFAULT%"), config->archPath()); + out = std::regex_replace(out, std::regex("%FIRM%"), config->firmPath()); Result ret = NONE; - snprintf(progressBarMsg, sizeof(progressBarMsg), message.c_str()); - showProgressBar = true; - progressbarType = ProgressBar::Downloading; + if (isARG) { + snprintf(progressBarMsg, sizeof(progressBarMsg), message.c_str()); + showProgressBar = true; + progressbarType = ProgressBar::Downloading; - s32 prio = 0; - svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); - thread = threadCreate((ThreadFunc)Animation::displayProgressBar, NULL, 64 * 1024, prio - 1, -2, false); + s32 prio = 0; + svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); + thread = threadCreate((ThreadFunc)Animation::displayProgressBar, NULL, 64 * 1024, prio - 1, -2, false); + } if (downloadFromRelease("https://github.com/" + repo, file, out, includePrereleases) != 0) { - showProgressBar = false; + if (isARG) showProgressBar = false; + downloadFailed(); ret = FAILED_DOWNLOAD; - threadJoin(thread, U64_MAX); - threadFree(thread); + + if (isARG) { + threadJoin(thread, U64_MAX); + threadFree(thread); + } return ret; } - showProgressBar = false; - threadJoin(thread, U64_MAX); - threadFree(thread); + if (isARG) { + showProgressBar = false; + threadJoin(thread, U64_MAX); + threadFree(thread); + } + return ret; } -/* - Download a file. -*/ -Result ScriptUtils::downloadFile(const std::string &file, const std::string &output, const std::string &message) { +/* Download a file. */ +Result ScriptUtils::downloadFile(const std::string &file, const std::string &output, const std::string &message, bool isARG) { std::string out; out = std::regex_replace(output, std::regex("%3DSX%"), config->_3dsxPath()); out = std::regex_replace(out, std::regex("%NDS%"), config->ndsPath()); out = std::regex_replace(out, std::regex("%ARCHIVE_DEFAULT%"), config->archPath()); + out = std::regex_replace(out, std::regex("%FIRM%"), config->firmPath()); Result ret = NONE; - snprintf(progressBarMsg, sizeof(progressBarMsg), message.c_str()); - showProgressBar = true; - progressbarType = ProgressBar::Downloading; - s32 prio = 0; - svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); - thread = threadCreate((ThreadFunc)Animation::displayProgressBar, NULL, 64 * 1024, prio - 1, -2, false); + if (isARG) { + snprintf(progressBarMsg, sizeof(progressBarMsg), message.c_str()); + showProgressBar = true; + progressbarType = ProgressBar::Downloading; + + s32 prio = 0; + svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); + thread = threadCreate((ThreadFunc)Animation::displayProgressBar, NULL, 64 * 1024, prio - 1, -2, false); + } if (downloadToFile(file, out) != 0) { - showProgressBar = false; + if (isARG) showProgressBar = false; + downloadFailed(); ret = FAILED_DOWNLOAD; - threadJoin(thread, U64_MAX); - threadFree(thread); + + if (isARG) { + threadJoin(thread, U64_MAX); + threadFree(thread); + } + return ret; } - showProgressBar = false; - threadJoin(thread, U64_MAX); - threadFree(thread); + if (isARG) { + showProgressBar = false; + threadJoin(thread, U64_MAX); + threadFree(thread); + } + return ret; } -/* - Install CIA files. -*/ -void ScriptUtils::installFile(const std::string &file, bool updatingSelf, const std::string &message) { +/* Install CIA files. */ +void ScriptUtils::installFile(const std::string &file, bool updatingSelf, const std::string &message, bool isARG) { std::string in; in = std::regex_replace(file, std::regex("%ARCHIVE_DEFAULT%"), config->archPath()); in = std::regex_replace(in, std::regex("%3DSX%"), config->_3dsxPath()); in = std::regex_replace(in, std::regex("%NDS%"), config->ndsPath()); + in = std::regex_replace(in, std::regex("%FIRM%"), config->firmPath()); - snprintf(progressBarMsg, sizeof(progressBarMsg), message.c_str()); - showProgressBar = true; - progressbarType = ProgressBar::Installing; + if (isARG) { + snprintf(progressBarMsg, sizeof(progressBarMsg), message.c_str()); + showProgressBar = true; + progressbarType = ProgressBar::Installing; - s32 prio = 0; - svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); - thread = threadCreate((ThreadFunc)Animation::displayProgressBar, NULL, 64 * 1024, prio - 1, -2, false); + s32 prio = 0; + svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); + thread = threadCreate((ThreadFunc)Animation::displayProgressBar, NULL, 64 * 1024, prio - 1, -2, false); + } Title::Install(in.c_str(), updatingSelf); - showProgressBar = false; - threadJoin(thread, U64_MAX); - threadFree(thread); + + if (isARG) { + showProgressBar = false; + threadJoin(thread, U64_MAX); + threadFree(thread); + } } -/* - Extract files. -*/ -void ScriptUtils::extractFile(const std::string &file, const std::string &input, const std::string &output, const std::string &message) { +/* Extract files. */ +void ScriptUtils::extractFile(const std::string &file, const std::string &input, const std::string &output, const std::string &message, bool isARG) { + extractFilesCount = 0; + std::string out, in; in = std::regex_replace(file, std::regex("%ARCHIVE_DEFAULT%"), config->archPath()); in = std::regex_replace(in, std::regex("%3DSX%"), config->_3dsxPath()); in = std::regex_replace(in, std::regex("%NDS%"), config->ndsPath()); + in = std::regex_replace(in, std::regex("%FIRM%"), config->firmPath()); out = std::regex_replace(output, std::regex("%ARCHIVE_DEFAULT%"), config->archPath()); out = std::regex_replace(out, std::regex("%3DSX%"), config->_3dsxPath()); out = std::regex_replace(out, std::regex("%NDS%"), config->ndsPath()); + out = std::regex_replace(out, std::regex("%FIRM%"), config->firmPath()); + + if (isARG) { + snprintf(progressBarMsg, sizeof(progressBarMsg), message.c_str()); + showProgressBar = true; + progressbarType = ProgressBar::Extracting; + + s32 prio = 0; + svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); + thread = threadCreate((ThreadFunc)Animation::displayProgressBar, NULL, 64 * 1024, prio - 1, -2, false); + } - snprintf(progressBarMsg, sizeof(progressBarMsg), message.c_str()); - showProgressBar = true; filesExtracted = 0; - progressbarType = ProgressBar::Extracting; - - s32 prio = 0; - svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); - thread = threadCreate((ThreadFunc)Animation::displayProgressBar, NULL, 64 * 1024, prio - 1, -2, false); getExtractedSize(in, input); extractArchive(in, input, out); - showProgressBar = false; - threadJoin(thread, U64_MAX); - threadFree(thread); + + if (isARG) { + showProgressBar = false; + threadJoin(thread, U64_MAX); + threadFree(thread); + } } /* - Execute | run the script. + NOTE: This is for the argument system for now. This might get replaced completely with the Queue System in the future. */ Result ScriptUtils::runFunctions(nlohmann::json storeJson, int selection, const std::string &entry) { Result ret = NONE; // No Error as of yet. @@ -318,7 +355,7 @@ Result ScriptUtils::runFunctions(nlohmann::json storeJson, int selection, const message = Script[i]["message"]; } - if (!missing) ret = ScriptUtils::removeFile(file, message); + if (!missing) ret = ScriptUtils::removeFile(file, message, true); else ret = SYNTAX_ERROR; } else if (type == "downloadFile") { @@ -339,7 +376,7 @@ Result ScriptUtils::runFunctions(nlohmann::json storeJson, int selection, const message = Script[i]["message"]; } - if (!missing) ret = ScriptUtils::downloadFile(file, output, message); + if (!missing) ret = ScriptUtils::downloadFile(file, output, message, true); else ret = SYNTAX_ERROR; } else if (type == "downloadRelease") { @@ -368,7 +405,7 @@ Result ScriptUtils::runFunctions(nlohmann::json storeJson, int selection, const message = Script[i]["message"]; } - if (!missing) ret = ScriptUtils::downloadRelease(repo, file, output, includePrereleases, message); + if (!missing) ret = ScriptUtils::downloadRelease(repo, file, output, includePrereleases, message, true); else ret = SYNTAX_ERROR; } else if (type == "extractFile") { @@ -394,7 +431,7 @@ Result ScriptUtils::runFunctions(nlohmann::json storeJson, int selection, const message = Script[i]["message"]; } - if (!missing) ScriptUtils::extractFile(file, input, output, message); + if (!missing) ScriptUtils::extractFile(file, input, output, message, true); else ret = SYNTAX_ERROR; } else if (type == "installCia") { @@ -414,7 +451,7 @@ Result ScriptUtils::runFunctions(nlohmann::json storeJson, int selection, const message = Script[i]["message"]; } - if (!missing) ScriptUtils::installFile(file, updateSelf, message); + if (!missing) ScriptUtils::installFile(file, updateSelf, message, true); else ret = SYNTAX_ERROR; } else if (type == "mkdir") { @@ -488,7 +525,7 @@ Result ScriptUtils::runFunctions(nlohmann::json storeJson, int selection, const Message = Script[i]["message"]; } - if (!missing) ret = ScriptUtils::copyFile(source, destination, Message); + if (!missing) ret = ScriptUtils::copyFile(source, destination, Message, true); else ret = SYNTAX_ERROR; } else if (type == "move") { @@ -509,7 +546,7 @@ Result ScriptUtils::runFunctions(nlohmann::json storeJson, int selection, const Message = Script[i]["message"]; } - if (!missing) ret = ScriptUtils::renameFile(oldFile, newFile, Message); + if (!missing) ret = ScriptUtils::renameFile(oldFile, newFile, Message, true); else ret = SYNTAX_ERROR; } else if (type == "skip") { diff --git a/source/utils/sound.cpp b/source/utils/sound.cpp index bfcf3ae..162499c 100644 --- a/source/utils/sound.cpp +++ b/source/utils/sound.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 diff --git a/source/utils/stringutils.cpp b/source/utils/stringutils.cpp index da2e24e..2ba478b 100644 --- a/source/utils/stringutils.cpp +++ b/source/utils/stringutils.cpp @@ -1,6 +1,6 @@ /* * This file is part of Universal-Updater -* Copyright (C) 2019-2020 Universal-Team +* Copyright (C) 2019-2021 Universal-Team * * 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 @@ -26,6 +26,7 @@ #include "common.hpp" #include "stringutils.hpp" +#include /* To lowercase conversion. @@ -69,9 +70,9 @@ std::string StringUtils::formatBytes(int bytes) { if (bytes == 1) snprintf(out, sizeof(out), "%d Byte", bytes); else if (bytes < 1024) snprintf(out, sizeof(out), "%d Bytes", bytes); - else if (bytes < 1024 * 1024) snprintf(out, sizeof(out), "%.1f KB", (float)bytes / 1024); - else if (bytes < 1024 * 1024 * 1024) snprintf(out, sizeof(out), "%.1f MB", (float)bytes / 1024 / 1024); - else snprintf(out, sizeof(out), "%.1f GB", (float)bytes / 1024 / 1024 / 1024); + else if (bytes < 1024 * 1024) snprintf(out, sizeof(out), "%.1f KiB", (float)bytes / 1024); + else if (bytes < 1024 * 1024 * 1024) snprintf(out, sizeof(out), "%.1f MiB", (float)bytes / 1024 / 1024); + else snprintf(out, sizeof(out), "%.1f GiB", (float)bytes / 1024 / 1024 / 1024); return out; } @@ -104,4 +105,15 @@ std::string StringUtils::GetMarkString(int marks) { if (marks & favoriteMarks::SPADE) out += "♠"; return out; +} + +std::string StringUtils::format(const std::string &fmt_str, ...) { + va_list ap; + char *fp = nullptr; + va_start(ap, fmt_str); + vasprintf(&fp, fmt_str.c_str(), ap); + va_end(ap); + + std::unique_ptr formatted(fp, free); + return std::string(formatted.get()); } \ No newline at end of file