Some cleanup, add user and web icons

This commit is contained in:
XorTroll 2019-10-23 21:49:30 +02:00
parent f6b946d282
commit 79de9de4a1
15 changed files with 171 additions and 74 deletions

View file

@ -30,7 +30,8 @@ namespace am
GetSuspendedInfo,
LaunchHomebrewLibApplet,
LaunchHomebrewApplication,
OpenWebPage
OpenWebPage,
GetSelectedUser
};
struct QSuspendedInfo

View file

@ -75,9 +75,11 @@ namespace cfg
std::string icon_path;
};
struct MenuConfig
struct Config
{
std::string theme_name;
bool system_title_override_enabled;
};
static constexpr u32 CurrentThemeFormatVersion = 0;
@ -98,10 +100,10 @@ namespace cfg
std::string ProcessedThemeResource(ProcessedTheme &base, std::string resource_base);
ProcessedTheme ProcessTheme(Theme &base);
MenuConfig CreateNewAndLoadConfig();
MenuConfig LoadConfig();
MenuConfig EnsureConfig();
void SaveConfig(MenuConfig &cfg);
Config CreateNewAndLoadConfig();
Config LoadConfig();
Config EnsureConfig();
void SaveConfig(Config &cfg);
void SaveRecord(TitleRecord &record);
bool MoveRecordTo(TitleList &list, TitleRecord record, std::string folder);

View file

@ -31,6 +31,8 @@ using JSON = nlohmann::json;
#error uLaunch's release version isn't defined.
#endif
static constexpr size_t RawRGBAScreenBufferSize = 1280 * 720 * 4;
// Thanks SciresM
#define R_TRY(res_expr) \
({ \

View file

@ -206,31 +206,33 @@ namespace cfg
return processed;
}
MenuConfig CreateNewAndLoadConfig()
Config CreateNewAndLoadConfig()
{
MenuConfig cfg = {};
Config cfg = {};
cfg.system_title_override_enabled = false; // Due to ban risk, have it disabled by default.
SaveConfig(cfg);
return cfg;
}
MenuConfig LoadConfig()
Config LoadConfig()
{
MenuConfig cfg = {};
Config cfg = {};
auto [rc, cfgjson] = util::LoadJSONFromFile(CFG_CONFIG_JSON);
if(R_SUCCEEDED(rc))
{
cfg.theme_name = cfgjson.value("theme_name", "");
cfg.system_title_override_enabled = cfgjson.value("system_title_override_enabled", false);
}
return cfg;
}
MenuConfig EnsureConfig()
Config EnsureConfig()
{
if(!fs::ExistsFile(CFG_CONFIG_JSON)) return CreateNewAndLoadConfig();
return LoadConfig();
}
void SaveConfig(MenuConfig &cfg)
void SaveConfig(Config &cfg)
{
fs::DeleteFile(CFG_CONFIG_JSON);
JSON j = JSON::object();

View file

@ -22,20 +22,28 @@ namespace ui
void logo_Click();
void settings_Click();
void themes_Click();
void users_Click();
void web_Click();
void MoveFolder(std::string name, bool fade);
void OnInput(u64 down, u64 up, u64 held, pu::ui::Touch pos);
void SetUser(u128 user);
bool HandleFolderChange(cfg::TitleRecord &rec);
void HandleCloseSuspended();
void HandleHomebrewLaunch(cfg::TitleRecord &rec);
void HandleUserMenu();
void HandleWebPageOpen();
void HandleSettingsMenu();
void HandleThemesMenu();
private:
void *susptr;
bool last_hasconn;
u32 last_batterylvl;
bool last_charge;
pu::ui::elm::Image::Ref topMenuImage;
ClickableImage::Ref logo;
pu::ui::elm::Image::Ref connIcon;
ClickableImage::Ref users;
ClickableImage::Ref web;
ClickableImage::Ref logo;
pu::ui::elm::TextBlock::Ref timeText;
pu::ui::elm::TextBlock::Ref batteryText;
pu::ui::elm::Image::Ref batteryIcon;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 B

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 B

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -17,7 +17,7 @@ extern "C"
ui::QMenuApplication::Ref qapp;
cfg::TitleList list;
std::vector<cfg::TitleRecord> homebrew;
cfg::MenuConfig config;
cfg::Config config;
cfg::ProcessedTheme theme;
namespace qmenu
@ -68,7 +68,7 @@ int main()
auto [rc, smode] = am::QMenu_ProcessInput();
if(R_SUCCEEDED(rc))
{
app_buf = new u8[1280 * 720 * 4]();
app_buf = new u8[RawRGBAScreenBufferSize]();
qmenu::Initialize(smode == am::QMenuStartMode::StartupScreen); // Cache homebrew only on first launch
auto [_rc, menulist] = cfg::LoadTitleList(true);
list = menulist;

View file

@ -1,5 +1,6 @@
#include <ui/ui_MenuLayout.hpp>
#include <os/os_Titles.hpp>
#include <os/os_Account.hpp>
#include <util/util_Convert.hpp>
#include <util/util_Misc.hpp>
#include <ui/ui_QMenuApplication.hpp>
@ -9,7 +10,7 @@
extern ui::QMenuApplication::Ref qapp;
extern cfg::TitleList list;
extern std::vector<cfg::TitleRecord> homebrew;
extern cfg::MenuConfig config;
extern cfg::Config config;
extern cfg::ProcessedTheme theme;
namespace ui
@ -40,8 +41,16 @@ namespace ui
this->logo->SetHeight(60);
this->logo->SetOnClick(std::bind(&MenuLayout::logo_Click, this));
this->Add(this->logo);
this->connIcon = pu::ui::elm::Image::New(80, 53, cfg::ProcessedThemeResource(theme, "ui/NoConnectionIcon.png"));
this->Add(this->connIcon);
this->users = ClickableImage::New(270, 53, ""); // On layout creation, no user is still selected...
this->users->SetOnClick(std::bind(&MenuLayout::users_Click, this));
this->Add(this->users);
this->web = ClickableImage::New(340, 53, cfg::ProcessedThemeResource(theme, "ui/WebIcon.png"));
this->web->SetOnClick(std::bind(&MenuLayout::web_Click, this));
this->Add(this->web);
auto curtime = util::GetCurrentTime();
this->timeText = pu::ui::elm::TextBlock::New(515, 68, curtime);
this->timeText->SetColor(textclr);
@ -57,7 +66,6 @@ namespace ui
this->settings = ClickableImage::New(880, 53, cfg::ProcessedThemeResource(theme, "ui/SettingsIcon.png"));
this->settings->SetOnClick(std::bind(&MenuLayout::settings_Click, this));
this->Add(this->settings);
this->themes = ClickableImage::New(950, 53, cfg::ProcessedThemeResource(theme, "ui/ThemesIcon.png"));
this->themes->SetOnClick(std::bind(&MenuLayout::themes_Click, this));
this->Add(this->themes);
@ -503,28 +511,18 @@ namespace ui
{
if(!this->curfolder.empty()) this->MoveFolder("", true);
}
else if(down & KEY_MINUS)
{
SwkbdConfig swkbd;
swkbdCreate(&swkbd, 0);
swkbdConfigSetHeaderText(&swkbd, "Enter web page URL");
char url[500] = {0};
auto rc = swkbdShow(&swkbd, url, 500);
if(R_SUCCEEDED(rc))
{
WebCommonConfig web = {};
webPageCreate(&web, url);
webConfigSetWhitelist(&web, ".*");
else if(down & KEY_UP) this->menuToggle_Click();
else if(down & KEY_ZL) this->HandleUserMenu();
else if(down & KEY_L) this->HandleWebPageOpen();
else if(down & KEY_R) this->HandleSettingsMenu();
else if(down & KEY_ZR) this->HandleThemesMenu();
}
am::QMenuCommandWriter writer(am::QDaemonMessage::OpenWebPage);
writer.Write<WebCommonConfig>(web);
writer.FinishWrite();
qapp->StopPlayBGM();
qapp->CloseWithFadeOut();
return;
}
}
void MenuLayout::SetUser(u128 user)
{
this->users->SetImage(os::GetIconCacheImagePath(user));
this->users->SetWidth(50);
this->users->SetHeight(50);
}
void MenuLayout::menuToggle_Click()
@ -541,12 +539,22 @@ namespace ui
void MenuLayout::settings_Click()
{
qapp->CreateShowDialog("Settings", "Settings", {"Ok"}, true);
this->HandleSettingsMenu();
}
void MenuLayout::themes_Click()
{
qapp->CreateShowDialog("Themes", "Themes", {"Ok"}, true);
this->HandleThemesMenu();
}
void MenuLayout::users_Click()
{
this->HandleUserMenu();
}
void MenuLayout::web_Click()
{
this->HandleWebPageOpen();
}
bool MenuLayout::HandleFolderChange(cfg::TitleRecord &rec)
@ -607,24 +615,66 @@ namespace ui
}
else if(sopt == 1)
{
am::QMenuCommandWriter writer(am::QDaemonMessage::LaunchHomebrewApplication);
writer.Write<hb::TargetInput>(rec.nro_target);
writer.FinishWrite();
if(config.system_title_override_enabled)
{
am::QMenuCommandWriter writer(am::QDaemonMessage::LaunchHomebrewApplication);
writer.Write<hb::TargetInput>(rec.nro_target);
writer.FinishWrite();
am::QMenuCommandResultReader reader;
if(reader && R_SUCCEEDED(reader.GetReadResult()))
{
pu::audio::Play(this->sfxTitleLaunch);
qapp->StopPlayBGM();
qapp->CloseWithFadeOut();
return;
am::QMenuCommandResultReader reader;
if(reader && R_SUCCEEDED(reader.GetReadResult()))
{
pu::audio::Play(this->sfxTitleLaunch);
qapp->StopPlayBGM();
qapp->CloseWithFadeOut();
return;
}
else
{
auto rc = reader.GetReadResult();
qapp->CreateShowDialog("Title launch", "An error ocurred attempting to launch the title:\n" + util::FormatResultDisplay(rc) + " (" + util::FormatResultHex(rc) + ")", { "Ok" }, true);
}
reader.FinishRead();
}
else
{
auto rc = reader.GetReadResult();
qapp->CreateShowDialog("Title launch", "An error ocurred attempting to launch the title:\n" + util::FormatResultDisplay(rc) + " (" + util::FormatResultHex(rc) + ")", { "Ok" }, true);
}
reader.FinishRead();
else qapp->CreateShowDialog("Title launch", "System title launching (via flog) is disabled.\nYou can enable it in settings.\n\nNote that this system (unlike title override) could involve ban risk!\nUse it at your own risk.", { "Ok" }, true);
}
}
void MenuLayout::HandleUserMenu()
{
qapp->CreateShowDialog("Users", "Users", {"Ok"}, true);
}
void MenuLayout::HandleWebPageOpen()
{
SwkbdConfig swkbd;
swkbdCreate(&swkbd, 0);
swkbdConfigSetHeaderText(&swkbd, "Enter web page URL");
char url[500] = {0};
auto rc = swkbdShow(&swkbd, url, 500);
if(R_SUCCEEDED(rc))
{
WebCommonConfig web = {};
webPageCreate(&web, url);
webConfigSetWhitelist(&web, ".*");
am::QMenuCommandWriter writer(am::QDaemonMessage::OpenWebPage);
writer.Write<WebCommonConfig>(web);
writer.FinishWrite();
qapp->StopPlayBGM();
qapp->CloseWithFadeOut();
return;
}
}
void MenuLayout::HandleSettingsMenu()
{
qapp->CreateShowDialog("Settings", "Settings", {"Ok"}, true);
}
void MenuLayout::HandleThemesMenu()
{
qapp->CreateShowDialog("Themes", "Themes", {"Ok"}, true);
}
}

View file

@ -24,7 +24,7 @@ namespace ui
if(this->IsSuspended())
{
bool flag;
appletGetLastApplicationCaptureImageEx(app_buf, 1280 * 720 * 4, &flag);
appletGetLastApplicationCaptureImageEx(app_buf, RawRGBAScreenBufferSize, &flag);
}
auto [_rc, jui] = util::LoadJSONFromFile(cfg::ProcessedThemeResource(theme, "ui/UI.json"));
@ -45,8 +45,17 @@ namespace ui
case am::QMenuStartMode::Menu:
case am::QMenuStartMode::MenuApplicationSuspended:
case am::QMenuStartMode::MenuLaunchFailure:
{
// Returned from applet/title, QDaemon has the user but we don't, so...
am::QMenuCommandWriter writer(am::QDaemonMessage::GetSelectedUser);
writer.FinishWrite();
am::QMenuCommandResultReader res;
this->selected_user = res.Read<u128>();
res.FinishRead();
this->LoadMenu();
break;
}
default:
this->LoadLayout(this->startupLayout);
break;
@ -60,6 +69,7 @@ namespace ui
void QMenuApplication::LoadMenu()
{
this->menuLayout->SetUser(this->selected_user);
this->LoadLayout(this->menuLayout);
this->StartPlayBGM();
}

View file

@ -16,11 +16,11 @@ namespace QForegroundViewer
public byte[][] CaptureBackups = new byte[][]
{
new byte[1280 * 720 * 4], // Backups (5) so that new captures made by the main form don't replace old ones
new byte[1280 * 720 * 4],
new byte[1280 * 720 * 4],
new byte[1280 * 720 * 4],
new byte[1280 * 720 * 4],
new byte[ViewerMainForm.RawRGBAScreenBufferSize], // Backups (5) so that new captures made by the main form don't replace old ones
new byte[ViewerMainForm.RawRGBAScreenBufferSize],
new byte[ViewerMainForm.RawRGBAScreenBufferSize],
new byte[ViewerMainForm.RawRGBAScreenBufferSize],
new byte[ViewerMainForm.RawRGBAScreenBufferSize],
};
public ScreenshotForm(ViewerMainForm main)

View file

@ -16,14 +16,16 @@ namespace QForegroundViewer
private UsbK USB;
private Thread USBThread;
public const long RawRGBAScreenBufferSize = 1280 * 720 * 4;
public byte[][] CaptureBlocks = new byte[][]
{
new byte[1280 * 720 * 4], // Current block
new byte[1280 * 720 * 4], // Temporary blocks (5)
new byte[1280 * 720 * 4],
new byte[1280 * 720 * 4],
new byte[1280 * 720 * 4],
new byte[1280 * 720 * 4],
new byte[RawRGBAScreenBufferSize], // Current block
new byte[RawRGBAScreenBufferSize], // Temporary blocks (5)
new byte[RawRGBAScreenBufferSize],
new byte[RawRGBAScreenBufferSize],
new byte[RawRGBAScreenBufferSize],
new byte[RawRGBAScreenBufferSize],
};
public ViewerMainForm()

View file

@ -72,6 +72,8 @@ uLaunch is split, as mentioned above, into several sub-projects:
### QDaemon (SystemAppletQDaemon)
> This sub-project replaces qlaunch, aka title 0100000000001000.
This is the technically actual qlaunch reimplementation. However, to avoid memory issues it does not use any kind of UI (except console for development debug, which is removed for releases), and thus it uses 16MB of heap, while official HOME menu uses 56MB.
Instead, it uses [QMenu custom library applet](#qmenu-libraryappletqmenu) (launches and communicates with it) in order to display a proper menu UI.
@ -82,6 +84,8 @@ But, if all the functionality is handled by QMenu, why is this daemon process ne
### QMenu (LibraryAppletQMenu)
> This sub-project replaces eShop applet, aka title 010000000000100B.
This is the HOME menu the user will see and interact with. It contains all the UI and sounc functionality, password, themes...
### QHbTarget
@ -90,10 +94,14 @@ This is the name for two related projects, whose aim is to target and launch hom
#### System application (SystemApplicationQHbTarget)
> This sub-project replaces flog system application, aka title 01008BB00013C000.
This is the process which runs instead of flog, which is used to launch homebrew as applications.
#### Library applet (LibraryAppletQHbTarget)
> This sub-project replaces Mii applet, aka title 010000000000100B.
This is the same process but, like in normal HOME menu and Album, it runs homebrew as an applet. However, exiting homebrew here will exit to HOME menu instead of exiting to hbmenu.
### QForegroundViewer
@ -136,4 +144,6 @@ If you get a crash using uLaunch, please check:
- SciresM for [libstratosphere](https://github.com/Atmosphere-NX/libstratosphere).
- Switchbrew team for libnx and [hbloader](https://github.com/switchbrew/nx-hbloader), the base of *QHbTarget projects (they're some useful wrappers of hbloader in the end)
- Switchbrew team for libnx and [hbloader](https://github.com/switchbrew/nx-hbloader), the base of *QHbTarget projects (they're some useful wrappers of hbloader in the end)
- [Icons8](https://icons8.com/) website for a big part of the icons used by the default style.

View file

@ -262,6 +262,16 @@ void HandleQMenuMessage()
break;
}
case am::QDaemonMessage::GetSelectedUser:
{
reader.FinishRead();
am::QDaemonCommandResultWriter res(0);
res.Write<u128>(selected_uid);
res.FinishWrite();
break;
}
default:
break;
}
@ -273,7 +283,7 @@ namespace qdaemon
{
void Initialize()
{
app_buf = new u8[1280 * 720 * 4]();
app_buf = new u8[RawRGBAScreenBufferSize]();
fs::CreateDirectory(Q_BASE_SD_DIR);
// Debug testing mode
@ -340,15 +350,15 @@ namespace qdaemon
void ForegroundMain(void *arg)
{
u8 *demo = new (std::align_val_t(0x1000)) u8[1280 * 720 * 4]();
u8 *demo = new (std::align_val_t(0x1000)) u8[RawRGBAScreenBufferSize]();
usbCommsInitialize();
while(true)
{
appletUpdateLastForegroundCaptureImage();
bool tmp;
appletGetLastForegroundCaptureImageEx(demo, 1280 * 720 * 4, &tmp);
usbCommsWrite(demo, 1280 * 720 * 4);
appletGetLastForegroundCaptureImageEx(demo, RawRGBAScreenBufferSize, &tmp);
usbCommsWrite(demo, RawRGBAScreenBufferSize);
}
usbCommsExit();
delete[] demo;