Files
Horizon-OC/Source/sys-clk/manager/src/app_profiles_tab.cpp
souldbminersmwc 708be969cb hoc-sys/loader/config-pc/config-device - move unsafe freqs setting to hoc-sys
This allows stuff to be changed on the fly
2025-10-23 15:54:20 -04:00

245 lines
6.9 KiB
C++

/*
sys-clk manager, a sys-clk frontend homebrew
Copyright (C) 2019 natinusala
Copyright (C) 2019 p-sam
Copyright (C) 2019 m4xw
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 <https://www.gnu.org/licenses/>.
*/
#include "app_profiles_tab.h"
#include "app_profile_frame.h"
#include "ipc/client.h"
#include "ipc/ipc.h"
#include <cstring>
#include "utils.h"
#define PROFILE_BADGE "\uE3E0"
AppProfilesTab::AppProfilesTab()
{
// Filter toggle
this->filterListItem = new brls::ToggleListItem("Show applications with no profile", this->showEmptyProfiles, "", "Yes", "No");
filterListItem->getClickEvent()->subscribe([this](View* v)
{
this->refreshFilter();
});
this->addView(filterListItem);
// Spacing
this->addView(new brls::ListItemGroupSpacing());
// Applications list
NsApplicationRecord record;
uint64_t tid;
NsApplicationControlData controlData;
NacpLanguageEntry* langEntry = NULL;
Result rc;
size_t i = 0;
int recordCount = 0;
size_t controlSize = 0;
while (true)
{
// Record
rc = nsListApplicationRecord(&record, sizeof(record), i, &recordCount);
if (R_FAILED(rc))
{
errorResult("nsListApplicationRecord", rc);
break;
}
if(recordCount <= 0)
break;
tid = record.application_id;
// Control data
rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, tid, &controlData, sizeof(controlData), &controlSize);
if (R_FAILED(rc))
{
errorResult("nsGetApplicationControlData", rc);
break;
}
// Language entry
rc = nacpGetLanguageEntry(&controlData.nacp, &langEntry);
if (R_FAILED(rc))
{
errorResult("nacpGetLanguageEntry", rc);
break;
}
// Name
// if (!langEntry->name)
// {
// i++;
// continue;
// }
Title* title = (Title*) malloc(sizeof(Title));
title->tid = tid;
memset(title->name, 0, sizeof(title->name));
strncpy(title->name, langEntry->name, sizeof(title->name)-1);
memcpy(title->icon, controlData.icon, sizeof(title->icon));
// Profile
rc = sysclkIpcGetProfileCount(tid, &title->profileCount);
if (R_FAILED(rc))
{
errorResult("sysclkIpcGetProfileCount", rc);
free(title);
break;
}
// Add the ListItem
brls::ListItem *listItem = new brls::ListItem(formatListItemTitle(std::string(title->name)), "", formatTid(title->tid));
title->listItem = listItem;
this->items.push_back(listItem);
if (title->profileCount > 0)
{
listItem->setValue(PROFILE_BADGE);
this->profilesItems.push_back(listItem);
}
else
{
this->emptyProfilesItems.push_back(listItem);
if (!this->showEmptyProfiles)
listItem->collapse(false);
}
listItem->setThumbnail(title->icon, sizeof(title->icon));
listItem->getClickEvent()->subscribe([this, title](View* view) {
this->editingTitle = title;
AppProfileFrame* profileFrame = new AppProfileFrame(title);
brls::Application::pushView(profileFrame, brls::ViewAnimation::SLIDE_LEFT);
});
this->addView(listItem);
this->titles.push_back(title);
i++;
}
// Empty list message
this->emptyListLabel = new brls::Label(brls::LabelStyle::REGULAR, "", true);
this->addView(emptyListLabel);
this->updateEmptyListLabel(false);
}
void AppProfilesTab::updateEmptyListLabel(bool animate)
{
if (this->items.empty())
{
this->emptyListLabel->setText("\uE140 You don't have any application installed on your Nintendo Switch.");
this->emptyListLabel->show([](){}, animate);
}
else if (!this->showEmptyProfiles && this->profilesItems.empty())
{
this->emptyListLabel->setText("\uE140 You don't have any application with a defined profile at the moment.");
this->emptyListLabel->show([](){}, animate);
}
else
{
this->emptyListLabel->hide([](){}, animate);
}
}
AppProfilesTab::~AppProfilesTab()
{
for (Title* title : this->titles)
free(title);
this->titles.clear();
}
void AppProfilesTab::willAppear(bool resetState)
{
if (this->editingTitle != nullptr)
{
bool hadProfiles = this->editingTitle->profileCount > 0;
Result rc = sysclkIpcGetProfileCount(this->editingTitle->tid, &this->editingTitle->profileCount);
bool hasProfiles = this->editingTitle->profileCount > 0;
if (R_FAILED(rc))
{
errorResult("sysclkIpcGetProfileCount", rc);
this->editingTitle = nullptr;
return;
}
// Update the profile badge
if (hasProfiles)
this->editingTitle->listItem->setValue(PROFILE_BADGE);
else
this->editingTitle->listItem->setValue("");
// Update lists
// Remove from emptyProfilesItems if it didn't have a profile
// but has one now
// Add to profilesItems
if (!hadProfiles && hasProfiles)
{
this->emptyProfilesItems.erase(std::remove(this->emptyProfilesItems.begin(), this->emptyProfilesItems.end(), this->editingTitle->listItem), this->emptyProfilesItems.end());
this->profilesItems.push_back(this->editingTitle->listItem);
}
// Add to emptyProfilesItems if it had a profile but doesn't
// has one now
// Remove from profilesItems
if (hadProfiles && !hasProfiles)
{
this->emptyProfilesItems.push_back(this->editingTitle->listItem);
this->profilesItems.erase(std::remove(this->profilesItems.begin(), this->profilesItems.end(), this->editingTitle->listItem), this->profilesItems.end());
}
// Refresh the filter
this->refreshFilter();
// Cleanup
this->editingTitle = nullptr;
}
}
void AppProfilesTab::refreshFilter()
{
this->showEmptyProfiles = this->filterListItem->getToggleState();
for (brls::ListItem *listItem : this->emptyProfilesItems)
{
if (this->showEmptyProfiles)
listItem->expand();
else
listItem->collapse();
this->updateEmptyListLabel();
}
}