mirror of
https://github.com/DarkStore-3DS/DarkStore.git
synced 2026-07-03 00:39:02 +00:00
WIP: Argument | Shortcut support.
This commit is contained in:
@@ -75,6 +75,7 @@ bool Msg::promptMsg(const std::string &promptMsg) {
|
||||
Gui::clearTextBufs();
|
||||
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
|
||||
C2D_TargetClear(Top, TRANSPARENT);
|
||||
C2D_TargetClear(Bottom, TRANSPARENT);
|
||||
|
||||
GFX::DrawTop();
|
||||
Gui::Draw_Rect(0, 215, 400, 25, BAR_COLOR);
|
||||
@@ -82,6 +83,7 @@ bool Msg::promptMsg(const std::string &promptMsg) {
|
||||
Gui::DrawStringCentered(0, (240 - Gui::GetStringHeight(0.6f, promptMsg)) / 2, 0.6f, TEXT_COLOR, promptMsg, 395, 0, font);
|
||||
|
||||
Gui::DrawStringCentered(0, 218, 0.6f, TEXT_COLOR, Lang::get("CONFIRM_OR_CANCEL"), 390, 0, font);
|
||||
GFX::DrawBottom();
|
||||
C3D_FrameEnd(0);
|
||||
|
||||
for (int i = 0; i < 3; i++) gspWaitForVBlank();
|
||||
|
||||
@@ -103,6 +103,7 @@ Result Init::Initialize() {
|
||||
mkdir("sdmc:/3ds", 0777);
|
||||
mkdir("sdmc:/3ds/Universal-Updater", 0777);
|
||||
mkdir("sdmc:/3ds/Universal-Updater/stores", 0777);
|
||||
mkdir("sdmc:/3ds/Universal-Updater/shortcuts", 0777);
|
||||
|
||||
config = std::make_unique<Config>();
|
||||
Lang::load(config->language());
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ std::string Input::setkbdString(uint maxLength, const std::string &Text, const s
|
||||
}
|
||||
}
|
||||
|
||||
SwkbdButton ret = swkbdInputText(&state, temp, maxLength);
|
||||
SwkbdButton ret = swkbdInputText(&state, temp, sizeof(temp));
|
||||
temp[maxLength] = '\0';
|
||||
|
||||
return (ret == SWKBD_BUTTON_CONFIRM ? temp : "");
|
||||
|
||||
@@ -24,13 +24,69 @@
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "argumentParser.hpp"
|
||||
#include "common.hpp"
|
||||
#include "init.hpp"
|
||||
#include <dirent.h>
|
||||
#include <string>
|
||||
|
||||
#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.
|
||||
*/
|
||||
static void InitForARG() {
|
||||
gfxInitDefault();
|
||||
romfsInit();
|
||||
Gui::init();
|
||||
amInit();
|
||||
acInit();
|
||||
|
||||
/* Create Directories, if missing. */
|
||||
mkdir("sdmc:/3ds", 0777);
|
||||
mkdir("sdmc:/3ds/Universal-Updater", 0777);
|
||||
mkdir("sdmc:/3ds/Universal-Updater/stores", 0777);
|
||||
mkdir("sdmc:/3ds/Universal-Updater/shortcuts", 0777);
|
||||
|
||||
config = std::make_unique<Config>();
|
||||
Lang::load(config->language());
|
||||
Init::LoadFont();
|
||||
osSetSpeedupEnable(true); // Enable speed-up for New 3DS users.
|
||||
}
|
||||
|
||||
/*
|
||||
ARG Exit.
|
||||
*/
|
||||
static Result ExitForARG() {
|
||||
Gui::exit();
|
||||
Init::UnloadFont();
|
||||
gfxExit();
|
||||
cfguExit();
|
||||
acExit();
|
||||
amExit();
|
||||
romfsExit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc > 0) _3dsxPath = argv[0];
|
||||
|
||||
/* 4 --> Argument mode. */
|
||||
if (argc == ARG_AMOUNT) {
|
||||
InitForARG();
|
||||
|
||||
const std::string file = argv[1];
|
||||
const std::string entry = argv[2];
|
||||
int dlIndex = atoi(argv[3]);
|
||||
|
||||
std::unique_ptr<ArgumentParser> arg = std::make_unique<ArgumentParser>(file, entry, dlIndex);
|
||||
|
||||
if (arg->GetValid()) arg->Execute(); // Execute, if valid.
|
||||
else Msg::waitMsg(Lang::get("ARGUMENT_INVALID"));
|
||||
return ExitForARG();
|
||||
}
|
||||
|
||||
return Init::MainLoop();
|
||||
}
|
||||
@@ -318,7 +318,7 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
|
||||
else if (info[selection].Version < 3) Msg::waitMsg(Lang::get("UNISTORE_TOO_OLD"));
|
||||
else if (info[selection].Version > 3) Msg::waitMsg(Lang::get("UNISTORE_TOO_NEW"));
|
||||
else {
|
||||
store = std::make_unique<Store>(_STORE_PATH + info[selection].FileName);
|
||||
store = std::make_unique<Store>(_STORE_PATH + info[selection].FileName, info[selection].FileName);
|
||||
StoreUtils::ResetAll(store, meta, entries);
|
||||
config->lastStore(info[selection].FileName);
|
||||
StoreUtils::SortEntries(false, SortType::LAST_UPDATED, entries);
|
||||
@@ -340,7 +340,7 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
|
||||
else if (info[i + sPos].Version < 3) Msg::waitMsg(Lang::get("UNISTORE_TOO_OLD"));
|
||||
else if (info[i + sPos].Version > 3) Msg::waitMsg(Lang::get("UNISTORE_TOO_NEW"));
|
||||
else {
|
||||
store = std::make_unique<Store>(_STORE_PATH + info[i + sPos].FileName);
|
||||
store = std::make_unique<Store>(_STORE_PATH + info[i + sPos].FileName, info[i + sPos].FileName);
|
||||
StoreUtils::ResetAll(store, meta, entries);
|
||||
config->lastStore(info[i + sPos].FileName);
|
||||
doOut = true;
|
||||
|
||||
@@ -94,7 +94,7 @@ MainScreen::MainScreen() {
|
||||
}
|
||||
}
|
||||
|
||||
this->store = std::make_unique<Store>(_STORE_PATH + config->lastStore());
|
||||
this->store = std::make_unique<Store>(_STORE_PATH + config->lastStore(), config->lastStore());
|
||||
StoreUtils::ResetAll(this->store, this->meta, this->entries);
|
||||
StoreUtils::SortEntries(false, SortType::LAST_UPDATED, this->entries);
|
||||
};
|
||||
|
||||
@@ -24,11 +24,15 @@
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "keyboard.hpp"
|
||||
#include "scriptUtils.hpp"
|
||||
#include "storeUtils.hpp"
|
||||
#include "structs.hpp"
|
||||
#include <fstream>
|
||||
|
||||
#define DOWNLOAD_ENTRIES 7
|
||||
extern std::string _3dsxPath;
|
||||
extern bool is3DSX;
|
||||
extern bool touching(touchPosition touch, Structs::ButtonPos button);
|
||||
static const std::vector<Structs::ButtonPos> downloadBoxes = {
|
||||
{ 54, 32, 262, 22 },
|
||||
@@ -40,6 +44,45 @@ static const std::vector<Structs::ButtonPos> downloadBoxes = {
|
||||
{ 54, 212, 262, 22 }
|
||||
};
|
||||
|
||||
/*
|
||||
With this, we can create a shortcut. ;P
|
||||
|
||||
const std::string &entryName: The name of the Entry. AKA: The Title Name.
|
||||
int index: The Download index.
|
||||
const std::string &unistoreName: The name of the UniStore filename.
|
||||
const std::string &author: The author of the app.
|
||||
*/
|
||||
static void CreateShortcut(const std::string &entryName, int index, const std::string &unistoreName, const std::string &author) {
|
||||
std::string sName = Input::setkbdString(30, Lang::get("ENTER_SHORTCUT_FILENAME"), {});
|
||||
if (sName == "") sName = "tmp";
|
||||
std::ofstream out(config->shortcut() + "/" + sName + ".xml", std::ios::binary);
|
||||
|
||||
out << "<shortcut>" << std::endl;
|
||||
|
||||
/* Executable. */
|
||||
const std::string executable = _3dsxPath.substr(5, _3dsxPath.size()); // It must be '/3ds/...'.
|
||||
out << " <executable>" << executable << "</executable>" << std::endl;
|
||||
|
||||
/* Arguments. */
|
||||
out << " <arg>\"" << unistoreName << "\" \"" << entryName << "\" \"" << std::to_string(index) << "\"" << "</arg>" << std::endl;
|
||||
|
||||
/* Title. */
|
||||
const std::string title = Input::setkbdString(30, Lang::get("ENTER_TITLE_SHORTCUT"), {});
|
||||
if (title != "") out << " <name>" << title << "</name>" << std::endl;
|
||||
else out << " <name>" << entryName << "</name>" << std::endl;
|
||||
|
||||
/* Description. */
|
||||
const std::string desc = Input::setkbdString(50, Lang::get("ENTER_DESC_SHORTCUT"), {});
|
||||
if (desc != "") out << " <description>" << desc << "</description>" << std::endl;
|
||||
else out << " <description>" << entryName << "</description>" << std::endl;
|
||||
|
||||
/* Author and end. */
|
||||
out << " <author>" << author << "</author>" << std::endl;
|
||||
out << "</shortcut>" << std::endl;
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Draw the Download Entries part.
|
||||
|
||||
@@ -87,6 +130,15 @@ void StoreUtils::DownloadHandle(const std::unique_ptr<Store> &store, const std::
|
||||
smallDelay--;
|
||||
}
|
||||
|
||||
if ((hDown & KEY_Y) || (hDown & KEY_START)) {
|
||||
if (is3DSX) { // Only allow if 3DSX.
|
||||
if (Msg::promptMsg(Lang::get("CREATE_SHORTCUT"))) {
|
||||
CreateShortcut(entry->GetTitle(), store->GetDownloadIndex(), store->GetFileName(), entry->GetAuthor());
|
||||
Msg::waitMsg(Lang::get("SHORTCUT_CREATED"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hRepeat & KEY_DOWN) {
|
||||
if (entries.size() <= 0) return; // Smaller *than* 0 -> Invalid.
|
||||
|
||||
@@ -122,9 +174,7 @@ void StoreUtils::DownloadHandle(const std::unique_ptr<Store> &store, const std::
|
||||
for (int i = 0; i < DOWNLOAD_ENTRIES; i++) {
|
||||
if (touching(touch, downloadBoxes[i])) {
|
||||
if (i + store->GetDownloadSIndex() < (int)entries.size()) {
|
||||
const std::string tmp = Lang::get("EXECUTE_ENTRY") + "\n\n" + entries[i + store->GetDownloadSIndex()];
|
||||
|
||||
if (Msg::promptMsg(tmp)) {
|
||||
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);
|
||||
@@ -137,8 +187,7 @@ void StoreUtils::DownloadHandle(const std::unique_ptr<Store> &store, const std::
|
||||
if (smallDelay == 0 && hDown & KEY_A) {
|
||||
if (entries.size() <= 0) return; // Smaller *than* 0 -> Invalid.
|
||||
|
||||
const std::string tmp = Lang::get("EXECUTE_ENTRY") + "\n\n" + entries[store->GetDownloadIndex()];
|
||||
if (Msg::promptMsg(tmp)) {
|
||||
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);
|
||||
|
||||
@@ -63,7 +63,7 @@ static const Structs::ButtonPos back = { 52, 0, 24, 24 }; // Back arrow for dire
|
||||
|
||||
|
||||
static const std::vector<std::string> mainStrings = { "LANGUAGE", "SELECT_UNISTORE", "AUTO_UPDATE_SETTINGS_BTN", "GUI_SETTINGS_BTN", "DIRECTORY_SETTINGS_BTN", "CREDITS", "EXIT_APP" };
|
||||
static const std::vector<std::string> dirStrings = { "CHANGE_3DSX_PATH", "CHANGE_NDS_PATH", "CHANGE_ARCHIVE_PATH" };
|
||||
static const std::vector<std::string> dirStrings = { "CHANGE_3DSX_PATH", "CHANGE_NDS_PATH", "CHANGE_ARCHIVE_PATH", "CHANGE_SHORTCUT_PATH" };
|
||||
|
||||
/* Note: Украïнська is spelled using a latin i with dieresis to work in the system font */
|
||||
static const std::vector<std::string> languages = { "Bruh", "Dansk", "Deutsch", "English", "Español", "Français", "Italiano", "Lietuvių", "Magyar", "Polski", "Português", "Português (Brasil)", "Русский", "Украïнська", "日本語" };
|
||||
@@ -115,7 +115,7 @@ static void DrawSettingsDir(int selection) {
|
||||
GFX::DrawSprite(sprites_arrow_idx, back.x, back.y);
|
||||
Gui::DrawStringCentered(32, 2, 0.6, TEXT_COLOR, Lang::get("DIRECTORY_SETTINGS"), 240, 0, font);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
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);
|
||||
}
|
||||
@@ -293,18 +293,18 @@ static void SettingsHandleDir(int &page, int &selection, const std::unique_ptr<S
|
||||
}
|
||||
|
||||
if (hRepeat & KEY_DOWN) {
|
||||
if (selection < 2) selection++;
|
||||
if (selection < 3) selection++;
|
||||
else selection = 0;
|
||||
}
|
||||
|
||||
if (hRepeat & KEY_UP) {
|
||||
if (selection > 0) selection--;
|
||||
else selection = dirStrings.size()-1;
|
||||
else selection = dirStrings.size() - 1;
|
||||
}
|
||||
|
||||
if (hRepeat & KEY_RIGHT) {
|
||||
if (selection + 8 < (int)dirStrings.size()-1) selection += 8;
|
||||
else selection = dirStrings.size()-1;
|
||||
if (selection + 8 < (int)dirStrings.size() - 1) selection += 8;
|
||||
else selection = dirStrings.size() - 1;
|
||||
}
|
||||
|
||||
if (hRepeat & KEY_LEFT) {
|
||||
@@ -328,6 +328,10 @@ static void SettingsHandleDir(int &page, int &selection, const std::unique_ptr<S
|
||||
} else if (touching(touch, mainButtons[2])) {
|
||||
const std::string path = Overlays::SelectDir(config->archPath(), Lang::get("SELECT_DIR"), store);
|
||||
if (path != "") config->archPath(path);
|
||||
|
||||
} else if (touching(touch, mainButtons[3])) {
|
||||
const std::string path = Overlays::SelectDir(config->shortcut(), Lang::get("SELECT_DIR"), store);
|
||||
if (path != "") config->shortcut(path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,6 +353,11 @@ static void SettingsHandleDir(int &page, int &selection, const std::unique_ptr<S
|
||||
path = Overlays::SelectDir(config->archPath(), Lang::get("SELECT_DIR"), store);
|
||||
if (path != "") config->archPath(path);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
path = Overlays::SelectDir(config->shortcut(), Lang::get("SELECT_DIR"), store);
|
||||
if (path != "") config->shortcut(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-3
@@ -39,10 +39,19 @@ static bool firstStart = true;
|
||||
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) {
|
||||
this->update(file);
|
||||
this->SetC2DBGImage();
|
||||
Store::Store(const std::string &file, const std::string &file2, bool ARGMode) {
|
||||
this->fileName = file2;
|
||||
|
||||
if (!ARGMode) {
|
||||
this->update(file);
|
||||
this->SetC2DBGImage();
|
||||
|
||||
} else {
|
||||
this->LoadFromFile(file);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 "argumentParser.hpp"
|
||||
#include "common.hpp"
|
||||
#include "scriptUtils.hpp"
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
The constructor of the Argument Parser.
|
||||
|
||||
const std::string &file: Const Reference to the file.
|
||||
const std::string &entry: Const Reference to the Entry Title name.
|
||||
int dlIndex: The Download index.
|
||||
*/
|
||||
ArgumentParser::ArgumentParser(const std::string &file, const std::string &entry, int dlIndex) {
|
||||
if (dlIndex != -1 || file != "") {
|
||||
this->file = file;
|
||||
this->entry = entry;
|
||||
this->dlIndex = dlIndex;
|
||||
|
||||
this->Load();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Prepare UniStore and get valid state.
|
||||
*/
|
||||
void ArgumentParser::Load() {
|
||||
if (access((std::string(_STORE_PATH) + this->file).c_str(), F_OK) != 0) return;
|
||||
|
||||
this->store = std::make_unique<Store>(_STORE_PATH + this->file, this->file, true);
|
||||
if (!this->store->GetValid()) return;
|
||||
|
||||
for (int i = 0; i < this->store->GetStoreSize(); i++) {
|
||||
if (this->store->GetTitleEntry(i) == this->entry) {
|
||||
this->entryIndex = i;
|
||||
const std::vector<std::string> dlList = this->store->GetDownloadList(this->entryIndex);
|
||||
|
||||
if (dlList.empty()) return;
|
||||
|
||||
if ((int)dlList.size() >= this->dlIndex) {
|
||||
this->executeEntry = dlList[this->dlIndex];
|
||||
this->isValid = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Execute the Argument's entry, if valid.
|
||||
*/
|
||||
void ArgumentParser::Execute() {
|
||||
if (this->isValid) {
|
||||
if (Msg::promptMsg(Lang::get("EXECUTE_ENTRY") + "\n\n" + this->executeEntry)) {
|
||||
ScriptUtils::runFunctions(this->store->GetJson(), this->entryIndex, this->executeEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,6 +124,7 @@ Config::Config() {
|
||||
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"));
|
||||
|
||||
this->changesMade = false; // No changes made yet.
|
||||
}
|
||||
@@ -146,6 +147,7 @@ void Config::save() {
|
||||
this->setBool("UpdateCheck", this->updatecheck());
|
||||
this->setBool("UseBG", this->usebg());
|
||||
this->setBool("CustomFont", this->customfont());
|
||||
this->setString("Shortcut_Path", this->shortcut());
|
||||
|
||||
/* Write changes to file. */
|
||||
const std::string dump = this->json.dump(1, '\t');
|
||||
|
||||
Reference in New Issue
Block a user