update homebrew menu when app is installed from the appstore, add same effect to a few other menus (unused).
This commit is contained in:
@@ -192,6 +192,28 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto GetAccountList() -> std::vector<AccountProfileBase> {
|
||||||
|
std::vector<AccountProfileBase> out;
|
||||||
|
|
||||||
|
AccountUid uids[8];
|
||||||
|
s32 account_count;
|
||||||
|
if (R_SUCCEEDED(accountListAllUsers(uids, std::size(uids), &account_count))) {
|
||||||
|
for (s32 i = 0; i < account_count; i++) {
|
||||||
|
AccountProfile profile;
|
||||||
|
if (R_SUCCEEDED(accountGetProfile(&profile, uids[i]))) {
|
||||||
|
ON_SCOPE_EXIT(accountProfileClose(&profile));
|
||||||
|
|
||||||
|
AccountProfileBase base;
|
||||||
|
if (R_SUCCEEDED(accountProfileGet(&profile, nullptr, &base))) {
|
||||||
|
out.emplace_back(base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
// private:
|
// private:
|
||||||
static constexpr inline auto CONFIG_PATH = "/config/sphaira/config.ini";
|
static constexpr inline auto CONFIG_PATH = "/config/sphaira/config.ini";
|
||||||
static constexpr inline auto PLAYLOG_PATH = "/config/sphaira/playlog.ini";
|
static constexpr inline auto PLAYLOG_PATH = "/config/sphaira/playlog.ini";
|
||||||
|
|||||||
@@ -154,6 +154,8 @@ struct FsDirCollection {
|
|||||||
|
|
||||||
using FsDirCollections = std::vector<FsDirCollection>;
|
using FsDirCollections = std::vector<FsDirCollection>;
|
||||||
|
|
||||||
|
void SignalChange();
|
||||||
|
|
||||||
struct Menu;
|
struct Menu;
|
||||||
|
|
||||||
struct FsView final : Widget {
|
struct FsView final : Widget {
|
||||||
@@ -244,7 +246,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Sort();
|
void Sort();
|
||||||
void SortAndFindLastFile();
|
void SortAndFindLastFile(bool scan = false);
|
||||||
void SetIndexFromLastFile(const LastFile& last_file);
|
void SetIndexFromLastFile(const LastFile& last_file);
|
||||||
|
|
||||||
void OnDeleteCallback();
|
void OnDeleteCallback();
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ enum OrderType {
|
|||||||
using LayoutType = grid::LayoutType;
|
using LayoutType = grid::LayoutType;
|
||||||
|
|
||||||
auto GetNroEntries() -> std::span<const NroEntry>;
|
auto GetNroEntries() -> std::span<const NroEntry>;
|
||||||
|
void SignalChange();
|
||||||
|
|
||||||
struct Menu final : grid::Menu {
|
struct Menu final : grid::Menu {
|
||||||
Menu();
|
Menu();
|
||||||
@@ -47,7 +48,7 @@ private:
|
|||||||
void InstallHomebrew();
|
void InstallHomebrew();
|
||||||
void ScanHomebrew();
|
void ScanHomebrew();
|
||||||
void Sort();
|
void Sort();
|
||||||
void SortAndFindLastFile();
|
void SortAndFindLastFile(bool scan = false);
|
||||||
void FreeEntries();
|
void FreeEntries();
|
||||||
void OnLayoutChange();
|
void OnLayoutChange();
|
||||||
|
|
||||||
@@ -61,6 +62,7 @@ private:
|
|||||||
std::vector<NroEntry> m_entries{};
|
std::vector<NroEntry> m_entries{};
|
||||||
s64 m_index{}; // where i am in the array
|
s64 m_index{}; // where i am in the array
|
||||||
std::unique_ptr<List> m_list{};
|
std::unique_ptr<List> m_list{};
|
||||||
|
bool m_dirty{};
|
||||||
|
|
||||||
option::OptionLong m_sort{INI_SECTION, "sort", SortType::SortType_AlphabeticalStar};
|
option::OptionLong m_sort{INI_SECTION, "sort", SortType::SortType_AlphabeticalStar};
|
||||||
option::OptionLong m_order{INI_SECTION, "order", OrderType::OrderType_Descending};
|
option::OptionLong m_order{INI_SECTION, "order", OrderType::OrderType_Descending};
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ enum OrderType {
|
|||||||
|
|
||||||
using LayoutType = grid::LayoutType;
|
using LayoutType = grid::LayoutType;
|
||||||
|
|
||||||
|
void SignalChange();
|
||||||
|
|
||||||
struct Menu final : grid::Menu {
|
struct Menu final : grid::Menu {
|
||||||
Menu(u32 flags);
|
Menu(u32 flags);
|
||||||
~Menu();
|
~Menu();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "ui/menus/appstore.hpp"
|
#include "ui/menus/appstore.hpp"
|
||||||
|
#include "ui/menus/homebrew.hpp"
|
||||||
#include "ui/sidebar.hpp"
|
#include "ui/sidebar.hpp"
|
||||||
#include "ui/popup_list.hpp"
|
#include "ui/popup_list.hpp"
|
||||||
#include "ui/progress_box.hpp"
|
#include "ui/progress_box.hpp"
|
||||||
@@ -798,6 +799,7 @@ void EntryMenu::UpdateOptions() {
|
|||||||
App::Push(std::make_shared<ProgressBox>(m_entry.image.image, "Downloading "_i18n, m_entry.title, [this](auto pbox){
|
App::Push(std::make_shared<ProgressBox>(m_entry.image.image, "Downloading "_i18n, m_entry.title, [this](auto pbox){
|
||||||
return InstallApp(pbox, m_entry);
|
return InstallApp(pbox, m_entry);
|
||||||
}, [this](Result rc){
|
}, [this](Result rc){
|
||||||
|
homebrew::SignalChange();
|
||||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
@@ -813,6 +815,7 @@ void EntryMenu::UpdateOptions() {
|
|||||||
App::Push(std::make_shared<ProgressBox>(m_entry.image.image, "Uninstalling "_i18n, m_entry.title, [this](auto pbox){
|
App::Push(std::make_shared<ProgressBox>(m_entry.image.image, "Uninstalling "_i18n, m_entry.title, [this](auto pbox){
|
||||||
return UninstallApp(pbox, m_entry);
|
return UninstallApp(pbox, m_entry);
|
||||||
}, [this](Result rc){
|
}, [this](Result rc){
|
||||||
|
homebrew::SignalChange();
|
||||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
namespace sphaira::ui::menu::filebrowser {
|
namespace sphaira::ui::menu::filebrowser {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constinit UEvent g_change_uevent;
|
||||||
|
|
||||||
constexpr FsEntry FS_ENTRY_DEFAULT{
|
constexpr FsEntry FS_ENTRY_DEFAULT{
|
||||||
"microSD card", "/", FsType::Sd, FsEntryFlag_Assoc,
|
"microSD card", "/", FsType::Sd, FsEntryFlag_Assoc,
|
||||||
};
|
};
|
||||||
@@ -289,6 +291,10 @@ auto GetRomIcon(fs::Fs* fs, ProgressBox* pbox, std::string filename, const RomDa
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
void SignalChange() {
|
||||||
|
ueventSignal(&g_change_uevent);
|
||||||
|
}
|
||||||
|
|
||||||
FsView::FsView(Menu* menu, const fs::FsPath& path, const FsEntry& entry, ViewSide side) : m_menu{menu}, m_side{side} {
|
FsView::FsView(Menu* menu, const fs::FsPath& path, const FsEntry& entry, ViewSide side) : m_menu{menu}, m_side{side} {
|
||||||
this->SetActions(
|
this->SetActions(
|
||||||
std::make_pair(Button::L2, Action{[this](){
|
std::make_pair(Button::L2, Action{[this](){
|
||||||
@@ -1083,13 +1089,17 @@ void FsView::Sort() {
|
|||||||
std::sort(m_entries_current.begin(), m_entries_current.end(), sorter);
|
std::sort(m_entries_current.begin(), m_entries_current.end(), sorter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FsView::SortAndFindLastFile() {
|
void FsView::SortAndFindLastFile(bool scan) {
|
||||||
std::optional<LastFile> last_file;
|
std::optional<LastFile> last_file;
|
||||||
if (!m_path.empty() && !m_entries_current.empty()) {
|
if (!m_path.empty() && !m_entries_current.empty()) {
|
||||||
last_file = LastFile(GetEntry().name, m_index, m_list->GetYoff(), m_entries_current.size());
|
last_file = LastFile(GetEntry().name, m_index, m_list->GetYoff(), m_entries_current.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
Sort();
|
if (scan) {
|
||||||
|
Scan(m_path);
|
||||||
|
} else {
|
||||||
|
Sort();
|
||||||
|
}
|
||||||
|
|
||||||
if (last_file.has_value()) {
|
if (last_file.has_value()) {
|
||||||
SetIndexFromLastFile(*last_file);
|
SetIndexFromLastFile(*last_file);
|
||||||
@@ -1851,12 +1861,22 @@ Menu::Menu(u32 flags) : MenuBase{"FileBrowser"_i18n, flags} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
view = view_left = std::make_shared<FsView>(this, ViewSide::Left);
|
view = view_left = std::make_shared<FsView>(this, ViewSide::Left);
|
||||||
|
ueventCreate(&g_change_uevent, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu::~Menu() {
|
Menu::~Menu() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::Update(Controller* controller, TouchInfo* touch) {
|
void Menu::Update(Controller* controller, TouchInfo* touch) {
|
||||||
|
if (R_SUCCEEDED(waitSingle(waiterForUEvent(&g_change_uevent), 0))) {
|
||||||
|
if (IsSplitScreen()) {
|
||||||
|
view_left->SortAndFindLastFile(true);
|
||||||
|
view_right->SortAndFindLastFile(true);
|
||||||
|
} else {
|
||||||
|
view->SortAndFindLastFile(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// workaround the buttons not being display properly.
|
// workaround the buttons not being display properly.
|
||||||
// basically, inherit all actions from the view, draw them,
|
// basically, inherit all actions from the view, draw them,
|
||||||
// then restore state after.
|
// then restore state after.
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
#include "i18n.hpp"
|
#include "i18n.hpp"
|
||||||
#include "image.hpp"
|
#include "image.hpp"
|
||||||
|
#include "swkbd.hpp"
|
||||||
|
|
||||||
#include "ui/menus/game_menu.hpp"
|
#include "ui/menus/game_menu.hpp"
|
||||||
#include "ui/sidebar.hpp"
|
#include "ui/sidebar.hpp"
|
||||||
@@ -945,6 +946,33 @@ Menu::Menu(u32 flags) : grid::Menu{"Games"_i18n, flags} {
|
|||||||
options->Add(std::make_shared<SidebarEntryBool>("Title cache"_i18n, m_title_cache.Get(), [this](bool& v_out){
|
options->Add(std::make_shared<SidebarEntryBool>("Title cache"_i18n, m_title_cache.Get(), [this](bool& v_out){
|
||||||
m_title_cache.Set(v_out);
|
m_title_cache.Set(v_out);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// todo: impl this.
|
||||||
|
#if 0
|
||||||
|
options->Add(std::make_shared<SidebarEntryCallback>("Create save"_i18n, [this](){
|
||||||
|
ui::PopupList::Items items{};
|
||||||
|
const auto accounts = App::GetAccountList();
|
||||||
|
for (auto& p : accounts) {
|
||||||
|
items.emplace_back(p.nickname);
|
||||||
|
}
|
||||||
|
|
||||||
|
fsCreateSaveDataFileSystem;
|
||||||
|
|
||||||
|
App::Push(std::make_shared<ui::PopupList>(
|
||||||
|
"Select user to create save for"_i18n, items, [accounts](auto op_index){
|
||||||
|
if (op_index) {
|
||||||
|
s64 out;
|
||||||
|
if (R_SUCCEEDED(swkbd::ShowNumPad(out, "Enter the save size"_i18n.c_str()))) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
// 1. Select user to create save for.
|
||||||
|
// 2. Enter the save size.
|
||||||
|
// 3. Enter the journal size (0 for default).
|
||||||
|
}));
|
||||||
|
#endif
|
||||||
}})
|
}})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ namespace sphaira::ui::menu::homebrew {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
Menu* g_menu{};
|
Menu* g_menu{};
|
||||||
|
constinit UEvent g_change_uevent;
|
||||||
|
|
||||||
auto GenerateStarPath(const fs::FsPath& nro_path) -> fs::FsPath {
|
auto GenerateStarPath(const fs::FsPath& nro_path) -> fs::FsPath {
|
||||||
fs::FsPath out{};
|
fs::FsPath out{};
|
||||||
@@ -35,6 +36,10 @@ void FreeEntry(NVGcontext* vg, NroEntry& e) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
void SignalChange() {
|
||||||
|
ueventSignal(&g_change_uevent);
|
||||||
|
}
|
||||||
|
|
||||||
auto GetNroEntries() -> std::span<const NroEntry> {
|
auto GetNroEntries() -> std::span<const NroEntry> {
|
||||||
if (!g_menu) {
|
if (!g_menu) {
|
||||||
return {};
|
return {};
|
||||||
@@ -139,6 +144,7 @@ Menu::Menu() : grid::Menu{"Homebrew"_i18n, MenuFlag_Tab} {
|
|||||||
);
|
);
|
||||||
|
|
||||||
OnLayoutChange();
|
OnLayoutChange();
|
||||||
|
ueventCreate(&g_change_uevent, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu::~Menu() {
|
Menu::~Menu() {
|
||||||
@@ -147,6 +153,14 @@ Menu::~Menu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Menu::Update(Controller* controller, TouchInfo* touch) {
|
void Menu::Update(Controller* controller, TouchInfo* touch) {
|
||||||
|
if (R_SUCCEEDED(waitSingle(waiterForUEvent(&g_change_uevent), 0))) {
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_dirty) {
|
||||||
|
SortAndFindLastFile(true);
|
||||||
|
}
|
||||||
|
|
||||||
MenuBase::Update(controller, touch);
|
MenuBase::Update(controller, touch);
|
||||||
m_list->OnUpdate(controller, touch, m_index, m_entries.size(), [this](bool touch, auto i) {
|
m_list->OnUpdate(controller, touch, m_index, m_entries.size(), [this](bool touch, auto i) {
|
||||||
if (touch && m_index == i) {
|
if (touch && m_index == i) {
|
||||||
@@ -297,6 +311,7 @@ void Menu::ScanHomebrew() {
|
|||||||
|
|
||||||
this->Sort();
|
this->Sort();
|
||||||
SetIndex(0);
|
SetIndex(0);
|
||||||
|
m_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::Sort() {
|
void Menu::Sort() {
|
||||||
@@ -391,9 +406,13 @@ void Menu::Sort() {
|
|||||||
std::sort(m_entries.begin(), m_entries.end(), sorter);
|
std::sort(m_entries.begin(), m_entries.end(), sorter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::SortAndFindLastFile() {
|
void Menu::SortAndFindLastFile(bool scan) {
|
||||||
const auto path = m_entries[m_index].path;
|
const auto path = m_entries[m_index].path;
|
||||||
Sort();
|
if (scan) {
|
||||||
|
ScanHomebrew();
|
||||||
|
} else {
|
||||||
|
Sort();
|
||||||
|
}
|
||||||
SetIndex(0);
|
SetIndex(0);
|
||||||
|
|
||||||
s64 index = -1;
|
s64 index = -1;
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ constexpr u32 NX_SAVE_META_MAGIC = 0x4A4B5356; // JKSV
|
|||||||
constexpr u32 NX_SAVE_META_VERSION = 1;
|
constexpr u32 NX_SAVE_META_VERSION = 1;
|
||||||
constexpr const char* NX_SAVE_META_NAME = ".nx_save_meta.bin";
|
constexpr const char* NX_SAVE_META_NAME = ".nx_save_meta.bin";
|
||||||
|
|
||||||
|
constinit UEvent g_change_uevent;
|
||||||
|
|
||||||
// https://github.com/J-D-K/JKSV/issues/264#issuecomment-2618962807
|
// https://github.com/J-D-K/JKSV/issues/264#issuecomment-2618962807
|
||||||
struct NXSaveMeta {
|
struct NXSaveMeta {
|
||||||
u32 magic{}; // NX_SAVE_META_MAGIC
|
u32 magic{}; // NX_SAVE_META_MAGIC
|
||||||
@@ -714,6 +716,10 @@ void ThreadFunc(void* user) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
void SignalChange() {
|
||||||
|
ueventSignal(&g_change_uevent);
|
||||||
|
}
|
||||||
|
|
||||||
ThreadData::ThreadData() {
|
ThreadData::ThreadData() {
|
||||||
ueventCreate(&m_uevent, true);
|
ueventCreate(&m_uevent, true);
|
||||||
mutexInit(&m_mutex_id);
|
mutexInit(&m_mutex_id);
|
||||||
@@ -928,21 +934,7 @@ Menu::Menu(u32 flags) : grid::Menu{"Saves"_i18n, flags} {
|
|||||||
OnLayoutChange();
|
OnLayoutChange();
|
||||||
nsInitialize();
|
nsInitialize();
|
||||||
|
|
||||||
AccountUid uids[8];
|
m_accounts = App::GetAccountList();
|
||||||
s32 account_count;
|
|
||||||
if (R_SUCCEEDED(accountListAllUsers(uids, std::size(uids), &account_count))) {
|
|
||||||
for (s32 i = 0; i < account_count; i++) {
|
|
||||||
AccountProfile profile;
|
|
||||||
if (R_SUCCEEDED(accountGetProfile(&profile, uids[i]))) {
|
|
||||||
ON_SCOPE_EXIT(accountProfileClose(&profile));
|
|
||||||
|
|
||||||
AccountProfileBase base;
|
|
||||||
if (R_SUCCEEDED(accountProfileGet(&profile, nullptr, &base))) {
|
|
||||||
m_accounts.emplace_back(base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// try and find the last / default account and set that.
|
// try and find the last / default account and set that.
|
||||||
AccountUid uid{};
|
AccountUid uid{};
|
||||||
@@ -965,6 +957,7 @@ Menu::Menu(u32 flags) : grid::Menu{"Saves"_i18n, flags} {
|
|||||||
threadCreate(&m_thread, ThreadFunc, &m_thread_data, nullptr, 1024*32, THREAD_PRIO, THREAD_CORE);
|
threadCreate(&m_thread, ThreadFunc, &m_thread_data, nullptr, 1024*32, THREAD_PRIO, THREAD_CORE);
|
||||||
svcSetThreadCoreMask(m_thread.handle, THREAD_CORE, THREAD_AFFINITY_DEFAULT(THREAD_CORE));
|
svcSetThreadCoreMask(m_thread.handle, THREAD_CORE, THREAD_AFFINITY_DEFAULT(THREAD_CORE));
|
||||||
threadStart(&m_thread);
|
threadStart(&m_thread);
|
||||||
|
ueventCreate(&g_change_uevent, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu::~Menu() {
|
Menu::~Menu() {
|
||||||
@@ -982,6 +975,10 @@ Menu::~Menu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Menu::Update(Controller* controller, TouchInfo* touch) {
|
void Menu::Update(Controller* controller, TouchInfo* touch) {
|
||||||
|
if (R_SUCCEEDED(waitSingle(waiterForUEvent(&g_change_uevent), 0))) {
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_dirty) {
|
if (m_dirty) {
|
||||||
App::Notify("Updating application record list");
|
App::Notify("Updating application record list");
|
||||||
SortAndFindLastFile(true);
|
SortAndFindLastFile(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user