Refine node info UI and peer announcements

This commit is contained in:
liu weikai
2026-04-21 22:32:52 +08:00
parent a022d4af8b
commit 110fa96be8
10 changed files with 1721 additions and 1007 deletions
File diff suppressed because it is too large Load Diff
@@ -1,66 +1,10 @@
/**
* UI Wireframe / Layout Tree (Node Info - matches provided mock)
* --------------------------------------------------------------------
*
* Root (COLUMN)
* +------------------------------------------------------------------+
* | Header (TopBar) [< Back] NODE INFO [Battery] |
* +------------------------------------------------------------------+
* | TopRow (ROW, grow) |
* | +-------------------------+ +---------------------------------+ |
* | | Info Card (left) | | Location Card (right) | |
* | | +---------------------+ | | +---------------------------+ | |
* | | | Avatar (S) | | | | Title: Location | | |
* | | | Name: ALFA-3 | | | +---------------------------+ | |
* | | | Desc: Relay Node | | | | Map Placeholder | | |
* | | +---------------------+ | | | [Map image] | | |
* | | | ID: !a1b2c3 | | | +---------------------------+ | |
* | | | Role: Router | | | | Lat,Lon +/-Acc Alt | | |
* | | +---------------------+ | | +---------------------------+ | |
* | | | | | Updated: 2m ago | | |
* | +-------------------------+ | +---------------------------+ | |
* | +---------------------------------+ |
* | |
* | Link Panel (full width) |
* | +------------------------------------------------------------+ |
* | | Title: Link | |
* | +------------------------------------------------------------+ |
* | | RSSI: -112 SNR: 7.5 Ch: 478.875 SF: 7 BW: 125k | |
* | +------------------------------------------------------------+ |
* | | Hop: 2 Last heard: 18s | |
* | +------------------------------------------------------------+ |
* +------------------------------------------------------------------+
*
* Tree view:
* Root(COL)
* - Header
* - Content(COL)
* - TopRow(ROW, grow=1)
* - InfoCard(COL)
* - InfoHeader(ROW)
* - InfoFooter(ROW)
* - LocationCard(COL, grow=1)
* - LocationHeader
* - LocationMap(grow=1)
* - LocationCoords
* - LocationUpdated
* - LinkPanel(COL)
* - LinkHeader
* - LinkRow1
* - LinkRow2
*
* Preconditions:
* - Root uses LV_FLEX_FLOW_COLUMN.
* - TopRow uses LV_FLEX_FLOW_ROW.
* - LinkPanel uses LV_FLEX_FLOW_COLUMN.
*/
/**
* @file node_info_page_layout.cpp
* @brief Node info page layout
* @brief Node info page layout helpers
*/
#include "ui/screens/node_info/node_info_page_layout.h"
#include "ui/page/page_profile.h"
#include "ui/widgets/top_bar.h"
@@ -73,8 +17,36 @@ namespace layout
namespace
{
constexpr lv_coord_t kScreenWidth = 480;
constexpr lv_coord_t kBaseContentHeight = 192;
lv_coord_t resolve_parent_width(lv_obj_t* parent)
{
if (parent)
{
const lv_coord_t width = lv_obj_get_width(parent);
if (width > 0)
{
return width;
}
}
const lv_coord_t width = lv_display_get_physical_horizontal_resolution(nullptr);
return width > 0 ? width : 320;
}
lv_coord_t resolve_parent_height(lv_obj_t* parent)
{
if (parent)
{
const lv_coord_t height = lv_obj_get_height(parent);
if (height > 0)
{
return height;
}
}
const lv_coord_t height = lv_display_get_physical_vertical_resolution(nullptr);
return height > 0 ? height : 240;
}
lv_coord_t top_bar_height()
{
@@ -83,196 +55,45 @@ lv_coord_t top_bar_height()
: static_cast<lv_coord_t>(::ui::widgets::kTopBarHeight);
}
lv_coord_t screen_height()
{
return top_bar_height() + kBaseContentHeight;
}
constexpr int kContentPadX = 8;
constexpr int kContentPadY = 4;
constexpr int kCardGapX = 8;
constexpr int kRowGap = 8;
constexpr int kTopRowX = kContentPadX;
constexpr int kTopRowY = kContentPadY;
constexpr int kTopRowWidth = kScreenWidth - (kContentPadX * 2);
constexpr int kTopRowHeight = 118;
constexpr int kInfoCardWidth = 190;
constexpr int kInfoCardHeight = 118;
constexpr int kLocationCardWidth = 266;
constexpr int kLocationCardHeight = 118;
constexpr int kLinkPanelX = kContentPadX;
constexpr int kLinkPanelY = kTopRowY + kTopRowHeight + kRowGap;
constexpr int kLinkPanelWidth = kTopRowWidth;
constexpr int kLinkPanelHeight = 60;
constexpr int kLocationHeaderHeight = 22;
constexpr int kLocationMapHeight = 52;
constexpr int kLocationCoordsHeight = 18;
constexpr int kLocationUpdatedHeight = 18;
constexpr int kInfoHeaderHeight = 70;
constexpr int kInfoFooterHeight = 36;
constexpr int kLinkHeaderHeight = 20;
constexpr int kLinkRowHeight = 16;
void make_non_scrollable(lv_obj_t* obj)
void make_plain(lv_obj_t* obj)
{
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_OFF);
lv_obj_set_style_pad_all(obj, 0, 0);
lv_obj_set_style_border_width(obj, 0, 0);
lv_obj_set_style_radius(obj, 0, 0);
}
} // namespace
lv_obj_t* create_root(lv_obj_t* parent)
{
lv_obj_t* root = lv_obj_create(parent);
lv_obj_set_size(root, kScreenWidth, screen_height());
lv_obj_set_size(root, resolve_parent_width(parent), resolve_parent_height(parent));
lv_obj_set_pos(root, 0, 0);
lv_obj_set_style_pad_all(root, 0, 0);
make_non_scrollable(root);
make_plain(root);
return root;
}
lv_obj_t* create_header(lv_obj_t* root)
{
lv_obj_t* header = lv_obj_create(root);
lv_obj_set_size(header, kScreenWidth, top_bar_height());
lv_obj_set_size(header, lv_obj_get_width(root), top_bar_height());
lv_obj_set_pos(header, 0, 0);
make_non_scrollable(header);
make_plain(header);
return header;
}
lv_obj_t* create_content(lv_obj_t* root)
{
const lv_coord_t header_h = top_bar_height();
lv_obj_t* content = lv_obj_create(root);
lv_obj_set_size(content, kScreenWidth, kBaseContentHeight);
lv_obj_set_pos(content, 0, top_bar_height());
lv_obj_set_style_pad_all(content, 0, 0);
make_non_scrollable(content);
lv_obj_set_size(content, lv_obj_get_width(root), lv_obj_get_height(root) - header_h);
lv_obj_set_pos(content, 0, header_h);
make_plain(content);
return content;
}
lv_obj_t* create_top_row(lv_obj_t* content)
{
lv_obj_t* row = lv_obj_create(content);
lv_obj_set_size(row, kTopRowWidth, kTopRowHeight);
lv_obj_set_pos(row, kTopRowX, kTopRowY);
lv_obj_set_style_pad_all(row, 0, 0);
make_non_scrollable(row);
return row;
}
lv_obj_t* create_info_card(lv_obj_t* top_row)
{
lv_obj_t* card = lv_obj_create(top_row);
lv_obj_set_size(card, kInfoCardWidth, kInfoCardHeight);
lv_obj_set_pos(card, 0, 0);
lv_obj_set_style_pad_all(card, 0, 0);
make_non_scrollable(card);
return card;
}
lv_obj_t* create_info_header(lv_obj_t* info_card)
{
lv_obj_t* header = lv_obj_create(info_card);
lv_obj_set_size(header, kInfoCardWidth, kInfoHeaderHeight);
lv_obj_set_pos(header, 0, 0);
lv_obj_set_style_pad_all(header, 0, 0);
make_non_scrollable(header);
return header;
}
lv_obj_t* create_info_footer(lv_obj_t* info_card)
{
lv_obj_t* footer = lv_obj_create(info_card);
lv_obj_set_size(footer, 170, kInfoFooterHeight);
lv_obj_set_pos(footer, 10, 70);
lv_obj_set_style_pad_all(footer, 0, 0);
make_non_scrollable(footer);
return footer;
}
lv_obj_t* create_location_card(lv_obj_t* top_row)
{
lv_obj_t* card = lv_obj_create(top_row);
lv_obj_set_size(card, kLocationCardWidth, kLocationCardHeight);
lv_obj_set_pos(card, kInfoCardWidth + kCardGapX, 0);
lv_obj_set_style_pad_all(card, 0, 0);
make_non_scrollable(card);
return card;
}
lv_obj_t* create_location_header(lv_obj_t* location_card)
{
lv_obj_t* header = lv_obj_create(location_card);
lv_obj_set_size(header, kLocationCardWidth, kLocationHeaderHeight);
lv_obj_set_pos(header, 0, 0);
lv_obj_set_style_pad_all(header, 0, 0);
make_non_scrollable(header);
return header;
}
lv_obj_t* create_location_map(lv_obj_t* location_card)
{
lv_obj_t* map = lv_obj_create(location_card);
lv_obj_set_size(map, 246, kLocationMapHeight);
lv_obj_set_pos(map, 10, 30);
lv_obj_set_style_pad_all(map, 0, 0);
make_non_scrollable(map);
return map;
}
lv_obj_t* create_location_coords(lv_obj_t* location_card)
{
lv_obj_t* coords = lv_obj_create(location_card);
lv_obj_set_size(coords, 246, kLocationCoordsHeight);
lv_obj_set_pos(coords, 10, 86);
lv_obj_set_style_pad_all(coords, 0, 0);
make_non_scrollable(coords);
return coords;
}
lv_obj_t* create_location_updated(lv_obj_t* location_card)
{
lv_obj_t* updated = lv_obj_create(location_card);
lv_obj_set_size(updated, 246, kLocationUpdatedHeight);
lv_obj_set_pos(updated, 10, 106);
lv_obj_set_style_pad_all(updated, 0, 0);
make_non_scrollable(updated);
return updated;
}
lv_obj_t* create_link_panel(lv_obj_t* content)
{
lv_obj_t* panel = lv_obj_create(content);
lv_obj_set_size(panel, kLinkPanelWidth, kLinkPanelHeight);
lv_obj_set_pos(panel, kLinkPanelX, kLinkPanelY);
lv_obj_set_style_pad_all(panel, 0, 0);
make_non_scrollable(panel);
return panel;
}
lv_obj_t* create_link_header(lv_obj_t* link_panel)
{
lv_obj_t* header = lv_obj_create(link_panel);
lv_obj_set_size(header, kLinkPanelWidth, kLinkHeaderHeight);
lv_obj_set_pos(header, 0, 0);
lv_obj_set_style_pad_all(header, 0, 0);
make_non_scrollable(header);
return header;
}
lv_obj_t* create_link_row(lv_obj_t* link_panel)
{
lv_obj_t* row = lv_obj_create(link_panel);
lv_obj_set_size(row, kLinkPanelWidth, kLinkRowHeight);
lv_obj_set_style_pad_all(row, 0, 0);
make_non_scrollable(row);
return row;
}
} // namespace layout
} // namespace ui
} // namespace node_info
@@ -216,16 +216,16 @@ void enter(const shell::Host* host, lv_obj_t* parent)
lv_obj_center(stack);
lv_obj_t* title = lv_label_create(stack);
::ui::i18n::set_label_text(title, page_subtitle());
lv_obj_set_style_text_font(title, &lv_font_montserrat_18, 0);
::ui::i18n::set_label_text(title, page_subtitle());
s_status_label = lv_label_create(stack);
::ui::i18n::set_label_text(s_status_label, "Waiting for host...");
lv_obj_set_style_text_font(s_status_label, &lv_font_montserrat_18, 0);
::ui::i18n::set_label_text(s_status_label, "Waiting for host...");
s_count_label = lv_label_create(stack);
::ui::i18n::set_label_text(s_count_label, "RX: 0 TX: 0");
lv_obj_set_style_text_font(s_count_label, &lv_font_montserrat_16, 0);
::ui::i18n::set_label_text(s_count_label, "RX: 0 TX: 0");
if (!s_timer)
{
@@ -272,26 +272,26 @@ void enter(const shell::Host* host, lv_obj_t* parent)
if (!platform::ui::device::card_ready())
{
lv_obj_t* error_label = lv_label_create(s_content);
::ui::i18n::set_label_text(error_label, "SD Card Not Found\nPlease insert SD card");
lv_obj_center(error_label);
lv_obj_set_style_text_font(error_label, &lv_font_montserrat_18, LV_PART_MAIN);
lv_obj_set_style_text_color(error_label, lv_color_hex(0xCC0000), LV_PART_MAIN);
::ui::i18n::set_label_text(error_label, "SD Card Not Found\nPlease insert SD card");
lv_obj_center(error_label);
return;
}
s_status_label = lv_label_create(s_content);
::ui::i18n::set_label_text(s_status_label, "Initializing...");
lv_obj_center(s_status_label);
lv_obj_set_style_text_font(s_status_label, &lv_font_montserrat_18, LV_PART_MAIN);
lv_obj_set_style_text_color(s_status_label, lv_color_hex(0x3A2A1A), LV_PART_MAIN);
lv_obj_set_style_text_align(s_status_label, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN);
::ui::i18n::set_label_text(s_status_label, "Initializing...");
lv_obj_center(s_status_label);
lv_obj_t* info_label = lv_label_create(s_content);
::ui::i18n::set_label_text(info_label, "Press Back to exit USB mode");
lv_obj_align(info_label, LV_ALIGN_BOTTOM_MID, 0, -20);
lv_obj_set_style_text_font(info_label, &lv_font_montserrat_14, LV_PART_MAIN);
lv_obj_set_style_text_color(info_label, lv_color_hex(0x6A5646), LV_PART_MAIN);
lv_obj_set_style_text_opa(info_label, LV_OPA_80, LV_PART_MAIN);
::ui::i18n::set_label_text(info_label, "Press Back to exit USB mode");
lv_obj_align(info_label, LV_ALIGN_BOTTOM_MID, 0, -20);
update_status_label();