redesign, broadcast server crash fix

This commit is contained in:
2026-04-26 12:41:58 +03:00
parent 4ffa6ed970
commit 64b30e9835
20 changed files with 771 additions and 167 deletions
+78
View File
@@ -0,0 +1,78 @@
#pragma once
#include <pu/Plutonium>
#include <string>
namespace theme {
using pu::ui::Color;
namespace color {
constexpr Color BgBase{0x10, 0x14, 0x1C, 0xFF};
constexpr Color BgSurface{0x18, 0x1F, 0x2A, 0xFF};
constexpr Color BgSurface2{0x22, 0x2B, 0x39, 0xFF};
constexpr Color Scrim{0x00, 0x00, 0x00, 0xB8};
constexpr Color Primary{0xE2, 0x4B, 0x55, 0xFF};
constexpr Color PrimaryDim{0x9C, 0x33, 0x3A, 0xFF};
constexpr Color Accent{0x4A, 0xC2, 0xE0, 0xFF};
constexpr Color TextPrimary{0xF2, 0xF4, 0xF8, 0xFF};
constexpr Color TextSecondary{0xB6, 0xBE, 0xCB, 0xFF};
constexpr Color TextMuted{0x70, 0x7A, 0x8C, 0xFF};
constexpr Color Success{0x55, 0xC8, 0x8A, 0xFF};
constexpr Color Error{0xE0, 0x6C, 0x6C, 0xFF};
constexpr Color Warning{0xE6, 0xB4, 0x55, 0xFF};
constexpr Color Divider{0x2A, 0x33, 0x42, 0xFF};
constexpr Color FocusRing{0xE2, 0x4B, 0x55, 0xFF};
}
namespace space {
constexpr int xs = 4;
constexpr int sm = 8;
constexpr int md = 16;
constexpr int lg = 24;
constexpr int xl = 32;
constexpr int xxl = 48;
}
namespace radius {
constexpr int sm = 6;
constexpr int md = 12;
constexpr int lg = 20;
constexpr int pill = 9999;
}
namespace type {
constexpr int Display = 38;
constexpr int Title = 30;
constexpr int Body = 25;
constexpr int Label = 20;
constexpr int Caption = 18;
inline std::string font(int size) {
return "DefaultFont@" + std::to_string(size);
}
}
namespace layout {
constexpr int ScreenW = 1280;
constexpr int ScreenH = 720;
constexpr int HeaderH = 72;
constexpr int HintH = 56;
constexpr int ContentTop = HeaderH;
constexpr int ContentH = ScreenH - HeaderH - HintH;
}
namespace motion {
constexpr int FadeFrames = 20;
constexpr int SlideFrames = 14;
constexpr int SpinnerFrames = 72;
}
namespace font {
constexpr const char* Default = "Inter";
constexpr const char* Medium = "InterMedium";
}
}
+34 -2
View File
@@ -3,17 +3,49 @@
#include <title.hpp>
#include <account.hpp>
#include <unordered_map>
#include <vector>
#include <memory>
#include <ui/HeaderBar.hpp>
#include <ui/HintBar.hpp>
namespace ui {
enum class TitlesFocus { List, Actions };
enum class TitlesAction { Transfer, Receive };
class TitlesLayout : public pu::ui::Layout {
private:
pu::ui::elm::Menu::Ref titlesMenu;
std::unordered_map<AccountUid, pu::ui::elm::Menu::Ref> menuCache;
std::unordered_map<AccountUid, std::vector<pu::ui::elm::MenuItem::Ref>> menuCache;
bool m_inputLocked = false;
std::unique_ptr<HeaderBar> header;
std::unique_ptr<HintBar> hints;
pu::ui::elm::Rectangle::Ref panelBg;
pu::ui::elm::TextBlock::Ref panelTitle;
pu::ui::elm::TextBlock::Ref panelHint;
pu::ui::elm::Rectangle::Ref btnTransferBg;
pu::ui::elm::TextBlock::Ref btnTransferText;
pu::ui::elm::Rectangle::Ref btnReceiveBg;
pu::ui::elm::TextBlock::Ref btnReceiveText;
pu::ui::elm::TextBlock::Ref panelFooter;
pu::ui::elm::TextBlock::Ref emptyText;
pu::ui::elm::TextBlock::Ref emptySub;
TitlesFocus focus = TitlesFocus::List;
TitlesAction action = TitlesAction::Transfer;
int lockedListIndex = 0;
void refreshPanel();
void refreshButtons();
void updateHints();
void runTransfer(int index, Title& title);
void runReceive(int index, Title& title);
public:
TitlesLayout();
void InitTitles();
void LockInput() { m_inputLocked = true; }
void UnlockInput() { m_inputLocked = false; }
@@ -22,4 +54,4 @@ namespace ui {
PU_SMART_CTOR(TitlesLayout)
};
}
}
+55 -31
View File
@@ -1,51 +1,83 @@
#pragma once
#include <pu/Plutonium>
#include <Theme.hpp>
#include <util.hpp>
namespace ui {
class TransferOverlay : public pu::ui::Overlay {
private:
pu::ui::elm::Rectangle::Ref card;
pu::ui::elm::TextBlock::Ref titleText;
pu::ui::elm::TextBlock::Ref statusText;
pu::ui::elm::Rectangle::Ref progressTrack;
pu::ui::elm::ProgressBar::Ref progressBar;
pu::ui::elm::TextBlock::Ref indeterminateText;
pu::ui::elm::TextBlock::Ref hintText;
static constexpr int CardW = 720;
static constexpr int CardH = 360;
static constexpr int CardX = (theme::layout::ScreenW - CardW) / 2;
static constexpr int CardY = (theme::layout::ScreenH - CardH) / 2;
public:
static constexpr int OvlX = 200;
static constexpr int OvlY = 240;
static constexpr int OvlW = 880;
static constexpr int OvlH = 240;
TransferOverlay(const std::string &title)
: Overlay(OvlX, OvlY, OvlW, OvlH, pu::ui::Color(30, 30, 30, 220))
: Overlay(0, 0, theme::layout::ScreenW, theme::layout::ScreenH, theme::color::Scrim)
{
titleText = pu::ui::elm::TextBlock::New(40, 30, title);
titleText->SetColor(pu::ui::Color(255, 255, 255, 255));
using namespace theme;
statusText = pu::ui::elm::TextBlock::New(40, 90, "");
statusText->SetColor(pu::ui::Color(180, 180, 180, 255));
card = pu::ui::elm::Rectangle::New(
CardX, CardY, CardW, CardH, color::BgSurface, radius::lg);
progressBar = pu::ui::elm::ProgressBar::New(40, 140, OvlW - 80, 20, 100.0);
progressBar->SetProgressColor(pu::ui::Color(100, 180, 255, 255));
progressBar->SetBackgroundColor(pu::ui::Color(70, 70, 70, 255));
titleText = pu::ui::elm::TextBlock::New(
CardX + space::lg, CardY + space::lg, title);
titleText->SetFont(type::font(type::Title));
titleText->SetColor(color::TextPrimary);
hintText = pu::ui::elm::TextBlock::New(40, 195, "Press B to cancel");
hintText->SetColor(pu::ui::Color(130, 130, 130, 255));
statusText = pu::ui::elm::TextBlock::New(
CardX + space::lg,
CardY + space::lg + 56,
"");
statusText->SetFont(type::font(type::Body));
statusText->SetColor(color::TextSecondary);
int barX = CardX + space::lg;
int barY = CardY + space::lg + 56 + 56;
int barW = CardW - 2 * space::lg;
progressTrack = pu::ui::elm::Rectangle::New(
barX, barY, barW, 8, color::Divider, radius::sm);
progressBar = pu::ui::elm::ProgressBar::New(
barX, barY, barW, 8, 100.0);
progressBar->SetProgressColor(color::Primary);
progressBar->SetBackgroundColor(color::Divider);
indeterminateText = pu::ui::elm::TextBlock::New(
barX, barY - 4, "Preparing transfer...");
indeterminateText->SetFont(type::font(type::Body));
indeterminateText->SetColor(color::TextMuted);
indeterminateText->SetVisible(false);
hintText = pu::ui::elm::TextBlock::New(
CardX + space::lg,
CardY + CardH - space::lg - 18,
"B to cancel");
hintText->SetFont(type::font(type::Caption));
hintText->SetColor(color::TextMuted);
this->Add(card);
this->Add(titleText);
this->Add(statusText);
this->Add(progressTrack);
this->Add(progressBar);
this->Add(indeterminateText);
this->Add(hintText);
}
PU_SMART_CTOR(TransferOverlay)
void SetStatus(const std::string &status) {
static constexpr size_t MaxChars = 48;
if (status.size() > MaxChars) {
statusText->SetText(status.substr(0, MaxChars - 3) + "...");
} else {
statusText->SetText(status);
}
statusText->SetText(StringUtils::elide(status, 56));
}
void SetProgress(double val) {
@@ -53,17 +85,9 @@ namespace ui {
}
void SetProgressVisible(bool visible) {
progressTrack->SetVisible(visible);
progressBar->SetVisible(visible);
if (visible) {
this->SetHeight(OvlH);
this->SetY(OvlY);
hintText->SetY(195);
} else {
static constexpr int SmallH = 160;
this->SetHeight(SmallH);
this->SetY((720 - SmallH) / 2);
hintText->SetY(120);
}
indeterminateText->SetVisible(!visible);
}
};
+5
View File
@@ -1,5 +1,8 @@
#include <pu/Plutonium>
#include <const.h>
#include <ui/HeaderBar.hpp>
#include <ui/HintBar.hpp>
#include <memory>
namespace ui {
@@ -9,6 +12,8 @@ namespace ui {
pu::ui::elm::Menu::Ref usersMenu;
pu::ui::elm::Rectangle::Ref loadingBg;
pu::ui::elm::TextBlock::Ref loadingText;
std::unique_ptr<HeaderBar> header;
std::unique_ptr<HintBar> hints;
public:
+1
View File
@@ -70,6 +70,7 @@ namespace Account {
std::vector<AccountUid> ids(void);
AccountUid selectAccount(void);
std::string username(AccountUid id);
std::string iconPath(AccountUid id);
}
#endif
+6 -2
View File
@@ -1,2 +1,6 @@
#define BACKGROUND_COLOR COLOR("00FFFFFF")
#define COLOR(hex) pu::ui::Color::FromHex(hex)
#pragma once
#include <Theme.hpp>
#define COLOR(hex) pu::ui::Color::FromHex(hex)
#define BACKGROUND_COLOR theme::color::BgBase
+2 -2
View File
@@ -40,10 +40,10 @@ public:
return mLogger;
}
inline static const std::string INFO = "[ INFO]";
inline static const std::string INFO = "[INFO]";
inline static const std::string DEBUG = "[DEBUG]";
inline static const std::string ERROR = "[ERROR]";
inline static const std::string WARN = "[ WARN]";
inline static const std::string WARN = "[WARN]";
template <typename... Args>
void log(const std::string& level, const std::string& format = {}, Args... args)
+1
View File
@@ -2,6 +2,7 @@
int startSendingThread();
bool isServerTransferDone();
bool isServerTransferCancelled();
bool isServerWorkersIdle();
void cancelServerTransfer();
double getServerProgress();
std::string getServerStatusText();
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#include <pu/Plutonium>
#include <Theme.hpp>
namespace ui {
class Card {
public:
pu::ui::elm::Rectangle::Ref bg;
Card(pu::ui::Layout* parent, int x, int y, int w, int h,
pu::ui::Color color = theme::color::BgSurface,
int rad = theme::radius::lg) {
bg = pu::ui::elm::Rectangle::New(x, y, w, h, color, rad);
parent->Add(bg);
}
};
}
+86
View File
@@ -0,0 +1,86 @@
#pragma once
#include <pu/Plutonium>
#include <Theme.hpp>
#include <ui/UiContext.hpp>
#include <account.hpp>
namespace ui {
class HeaderBar {
private:
pu::ui::elm::Rectangle::Ref bg;
pu::ui::elm::Rectangle::Ref divider;
pu::ui::elm::TextBlock::Ref appName;
pu::ui::elm::TextBlock::Ref subtitle;
pu::ui::elm::Rectangle::Ref chipBg;
pu::ui::elm::Image::Ref avatar;
pu::ui::elm::TextBlock::Ref userName;
public:
HeaderBar(pu::ui::Layout* parent, const std::string& sub = "Save Transfer") {
using namespace theme;
bg = pu::ui::elm::Rectangle::New(
0, 0, layout::ScreenW, layout::HeaderH, color::BgSurface);
divider = pu::ui::elm::Rectangle::New(
0, layout::HeaderH - 1, layout::ScreenW, 1, color::Divider);
appName = pu::ui::elm::TextBlock::New(space::lg, 8, "NXST");
appName->SetFont(type::font(type::Title));
appName->SetColor(color::TextPrimary);
subtitle = pu::ui::elm::TextBlock::New(space::lg, 46, sub);
subtitle->SetFont(type::font(type::Caption));
subtitle->SetColor(color::TextMuted);
const int chipW = 280;
const int chipX = layout::ScreenW - chipW - space::lg;
chipBg = pu::ui::elm::Rectangle::New(
chipX, 16, chipW, 40,
color::BgSurface2, radius::pill);
chipBg->SetVisible(false);
avatar = pu::ui::elm::Image::New(chipX + 4, 20, "");
avatar->SetWidth(32);
avatar->SetHeight(32);
avatar->SetVisible(false);
userName = pu::ui::elm::TextBlock::New(chipX + 44, 24, "");
userName->SetFont(type::font(type::Body));
userName->SetColor(color::TextPrimary);
userName->SetVisible(false);
parent->Add(bg);
parent->Add(divider);
parent->Add(appName);
parent->Add(subtitle);
parent->Add(chipBg);
parent->Add(avatar);
parent->Add(userName);
}
void SetUser(const std::optional<AccountUid>& uid, const std::string& name) {
const bool show = uid.has_value();
chipBg->SetVisible(show);
userName->SetVisible(show);
if (show) {
userName->SetText(name);
std::string path = Account::iconPath(*uid);
if (!path.empty()) {
avatar->SetImage(path);
avatar->SetWidth(32);
avatar->SetHeight(32);
avatar->SetVisible(avatar->IsImageValid());
} else {
avatar->SetVisible(false);
}
} else {
avatar->SetVisible(false);
}
}
void SetSubtitle(const std::string& text) {
subtitle->SetText(text);
}
};
}
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include <pu/Plutonium>
#include <Theme.hpp>
#include <vector>
#include <string>
namespace ui {
struct Hint {
std::string glyph;
std::string label;
};
class HintBar {
private:
pu::ui::Layout* parent;
pu::ui::elm::Rectangle::Ref bg;
pu::ui::elm::Rectangle::Ref divider;
std::vector<pu::ui::elm::TextBlock::Ref> labels;
public:
HintBar(pu::ui::Layout* p) : parent(p) {
using namespace theme;
bg = pu::ui::elm::Rectangle::New(
0, layout::ScreenH - layout::HintH,
layout::ScreenW, layout::HintH, color::BgSurface);
divider = pu::ui::elm::Rectangle::New(
0, layout::ScreenH - layout::HintH,
layout::ScreenW, 1, color::Divider);
parent->Add(bg);
parent->Add(divider);
}
void SetHints(const std::vector<Hint>& hints) {
using namespace theme;
for (auto& l : labels) l->SetVisible(false);
labels.clear();
int x = layout::ScreenW - space::lg;
int y = layout::ScreenH - layout::HintH + 18;
for (auto it = hints.rbegin(); it != hints.rend(); ++it) {
std::string text = it->glyph + " " + it->label;
auto tb = pu::ui::elm::TextBlock::New(0, y, text);
tb->SetFont(type::font(type::Label));
tb->SetColor(color::TextSecondary);
int w = tb->GetWidth();
x -= w;
tb->SetX(x);
x -= space::xl;
parent->Add(tb);
labels.push_back(tb);
}
}
};
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include <optional>
#include <switch.h>
#include <account.hpp>
namespace ui {
struct UiContext {
std::optional<AccountUid> selectedUser;
std::string selectedUserName;
};
}
+1
View File
@@ -47,6 +47,7 @@ namespace StringUtils {
std::string removeAccents(std::string str);
std::string removeNotAscii(std::string str);
std::u16string UTF8toUTF16(const char* src);
std::string elide(const std::string& s, size_t maxChars);
}
#endif