mirror of
https://github.com/vicliu624/trail-mate.git
synced 2026-07-19 01:56:19 +00:00
222 lines
5.5 KiB
C++
222 lines
5.5 KiB
C++
#include "ui/startup_shell.h"
|
|
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <ctime>
|
|
|
|
#include "lvgl.h"
|
|
#include "platform/ui/screen_runtime.h"
|
|
#include "platform/ui/time_runtime.h"
|
|
#include "sys/clock.h"
|
|
#include "ui/app_runtime.h"
|
|
#include "ui/localization.h"
|
|
#include "ui/menu/menu_layout.h"
|
|
#include "ui/menu/menu_runtime.h"
|
|
#include "ui/ui_boot.h"
|
|
#include "ui/ui_common.h"
|
|
#include "ui/ui_status.h"
|
|
#include "ui/watch_face.h"
|
|
#include "ui/runtime/ui_feedback.h"
|
|
#include "ui_lvgl_ux_packs/ux/ux_menu_provider.h"
|
|
|
|
namespace ui::startup_shell
|
|
{
|
|
namespace
|
|
{
|
|
|
|
ui::menu::MenuModel s_ux_menu_model;
|
|
|
|
constexpr uint8_t kBootPresentFrameCount = 4;
|
|
constexpr uint32_t kBootPresentFrameDelayMs = 16;
|
|
|
|
bool resolve_display_time(struct tm* out_tm)
|
|
{
|
|
if (!out_tm)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (::platform::ui::time::localtime_now(out_tm))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
const std::time_t now = std::time(nullptr);
|
|
if (now <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const std::time_t local = ::platform::ui::time::apply_timezone_offset(now);
|
|
const std::tm* tmp = std::gmtime(&local);
|
|
if (!tmp)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
*out_tm = *tmp;
|
|
return true;
|
|
}
|
|
|
|
void present_boot_overlay_now()
|
|
{
|
|
for (uint8_t frame = 0; frame < kBootPresentFrameCount; ++frame)
|
|
{
|
|
if (lv_obj_t* top = lv_layer_top())
|
|
{
|
|
lv_obj_invalidate(top);
|
|
}
|
|
lv_timer_handler();
|
|
lv_refr_now(nullptr);
|
|
if (frame + 1U < kBootPresentFrameCount)
|
|
{
|
|
sys::sleep_ms(kBootPresentFrameDelayMs);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool format_menu_time(char* out, size_t out_len)
|
|
{
|
|
if (!out || out_len < 6)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
struct tm info
|
|
{
|
|
};
|
|
if (!resolve_display_time(&info))
|
|
{
|
|
return false;
|
|
}
|
|
strftime(out, out_len, "%H:%M", &info);
|
|
return true;
|
|
}
|
|
|
|
menu_runtime::Hooks::WatchFaceHooks defaultWatchFaceHooks()
|
|
{
|
|
menu_runtime::Hooks::WatchFaceHooks hooks{};
|
|
hooks.create = watch_face_create;
|
|
hooks.set_time = watch_face_set_time;
|
|
hooks.set_node_id = watch_face_set_node_id;
|
|
hooks.show = watch_face_show;
|
|
hooks.is_ready = watch_face_is_ready;
|
|
hooks.set_unlock_cb = watch_face_set_unlock_cb;
|
|
return hooks;
|
|
}
|
|
|
|
menu_runtime::Hooks buildMenuRuntimeHooks(const Hooks& hooks)
|
|
{
|
|
menu_runtime::Hooks runtime_hooks{};
|
|
runtime_hooks.format_time = format_menu_time;
|
|
runtime_hooks.show_main_menu = hooks.show_main_menu;
|
|
|
|
const auto default_watch_face = defaultWatchFaceHooks();
|
|
runtime_hooks.watch_face = hooks.watch_face;
|
|
if (!runtime_hooks.watch_face.create)
|
|
{
|
|
runtime_hooks.watch_face.create = default_watch_face.create;
|
|
}
|
|
if (!runtime_hooks.watch_face.set_time)
|
|
{
|
|
runtime_hooks.watch_face.set_time = default_watch_face.set_time;
|
|
}
|
|
if (!runtime_hooks.watch_face.set_node_id)
|
|
{
|
|
runtime_hooks.watch_face.set_node_id = default_watch_face.set_node_id;
|
|
}
|
|
if (!runtime_hooks.watch_face.show)
|
|
{
|
|
runtime_hooks.watch_face.show = default_watch_face.show;
|
|
}
|
|
if (!runtime_hooks.watch_face.is_ready)
|
|
{
|
|
runtime_hooks.watch_face.is_ready = default_watch_face.is_ready;
|
|
}
|
|
if (!runtime_hooks.watch_face.set_unlock_cb)
|
|
{
|
|
runtime_hooks.watch_face.set_unlock_cb = default_watch_face.set_unlock_cb;
|
|
}
|
|
return runtime_hooks;
|
|
}
|
|
|
|
platform::ui::screen::Hooks buildScreenSleepHooks(const Hooks& hooks)
|
|
{
|
|
platform::ui::screen::Hooks runtime_hooks{};
|
|
runtime_hooks.format_time = format_menu_time;
|
|
runtime_hooks.read_unread_count = ui::status::get_total_unread;
|
|
runtime_hooks.show_main_menu = hooks.show_main_menu;
|
|
runtime_hooks.on_wake_from_sleep = ui::menu_runtime::onWakeFromSleep;
|
|
return runtime_hooks;
|
|
}
|
|
|
|
void setBootLogLine(const char* line)
|
|
{
|
|
std::printf("[BOOT][UI] log line=%s\n", line ? line : "");
|
|
std::fflush(stdout);
|
|
ui::boot::set_log_line(line);
|
|
present_boot_overlay_now();
|
|
}
|
|
|
|
void beginBootUi(bool waking_from_sleep, const char* initial_line)
|
|
{
|
|
std::printf("[BOOT][UI] show waking=%d line=%s\n",
|
|
waking_from_sleep ? 1 : 0,
|
|
initial_line ? initial_line : "");
|
|
std::fflush(stdout);
|
|
if (!waking_from_sleep)
|
|
{
|
|
ui::boot::show();
|
|
setBootLogLine(initial_line);
|
|
}
|
|
}
|
|
|
|
void prepareBootResources()
|
|
{
|
|
::ui::i18n::reload_language();
|
|
ui::feedback::init();
|
|
}
|
|
|
|
void initializeShell(const Hooks& hooks)
|
|
{
|
|
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_black(), LV_PART_MAIN);
|
|
lv_obj_set_style_radius(lv_screen_active(), 0, 0);
|
|
|
|
ui::menu_layout::InitOptions menu_options{};
|
|
menu_options.messaging = hooks.messaging;
|
|
menu_options.apps = hooks.apps;
|
|
if (hooks.ux_pack_id != nullptr &&
|
|
ui_lvgl_ux::buildMenuForUxPack(hooks.ux_pack_id, s_ux_menu_model))
|
|
{
|
|
menu_options.ux_menu = &s_ux_menu_model;
|
|
}
|
|
ui::menu_layout::init(menu_options);
|
|
|
|
ui::menu_runtime::init(
|
|
lv_screen_active(), main_screen, ui::menu_layout::menuPanel(), buildMenuRuntimeHooks(hooks));
|
|
|
|
if (hooks.set_max_brightness)
|
|
{
|
|
hooks.set_max_brightness();
|
|
}
|
|
|
|
ui::menu_runtime::showWatchFace();
|
|
platform::ui::screen::init(buildScreenSleepHooks(hooks));
|
|
}
|
|
|
|
void finalizeStartup(bool waking_from_sleep)
|
|
{
|
|
std::printf("[BOOT][UI] ready waking=%d\n", waking_from_sleep ? 1 : 0);
|
|
std::fflush(stdout);
|
|
if (waking_from_sleep)
|
|
{
|
|
platform::ui::screen::update_user_activity();
|
|
}
|
|
|
|
ui::boot::mark_ready();
|
|
}
|
|
|
|
} // namespace ui::startup_shell
|