feat(ncm): 网易云客户端 v1 UI+播放链路 (agent-205) — os.meow.ncm: 登录页(真实unikey二维码+轮询状态机)/我的歌单(listview)/歌单详情/播放页(封面+seek+滚动歌词+竖横屏切换)/设置(音质默认Hi-res+缓存上限默认10G); 播放线程(缓存LRU+minimp3→ALSA UAPI直开hw:0,0); 媒体会话MSG_META上报+PLAYCTL接收(首真实媒体源)
ncm 1e331964 (text 764KB); 0 warning; 宿主离屏6页截图目检+真实QR可扫+qemu-mipsel干净启动+解码446xRT 真机待联调: ALSA时序/803扫码闭环/媒体会话联动/gbk大字库渲染
This commit is contained in:
1 parent
32543ac616
commit
21519ce2e4
23 files changed
+3255
No files matched your search
@@ -0,0 +1,133 @@
|
||||
/* app.c — os.meow.ncm 应用装配层:main + 组装 + 事件分发。
|
||||
*
|
||||
* 职责(对齐 hello_app/app.c):main 只做初始化/建页/跑事件循环/清理;把 meow_ui_run 的平铺输入
|
||||
* 回调(key/tap/swipe/tick/touch)路由到当前活动页。页面切换统一走 meow_view_page_push/pop/replace。
|
||||
* 播放线程(player_manager)+ 媒体会话 IPC 线程(ipc_media)在 main 起动、退出时停。
|
||||
*
|
||||
* 铁律(APPS.md §3.4.1):物理键禁映射——on_key 不处理任何键语义;返回=左缘左滑/返回钮/request_exit。
|
||||
* 左缘返回:播放页→歌单→主页→退出(登录页→退出)。
|
||||
*/
|
||||
#include "ncm_app_internal.h"
|
||||
#include <signal.h>
|
||||
|
||||
ncm_app_state_t g_st;
|
||||
ncm_play_run_t g_play = { .mu = PTHREAD_MUTEX_INITIALIZER,
|
||||
.state = NCM_PC_STOPPED, .cur_song = -1 };
|
||||
volatile int g_app_quit = 0;
|
||||
volatile int g_net_ready = 0;
|
||||
int g_host_mock = 0;
|
||||
|
||||
static meow_view *g_login_view, *g_home_view, *g_pl_view, *g_plr_view, *g_set_view;
|
||||
|
||||
static void on_sigterm(int s) { (void)s; meow_ui_request_exit(); }
|
||||
|
||||
/* ============================================================ */
|
||||
/* 事件分发:meow_ui_run 平铺回调 → 当前页 */
|
||||
/* ============================================================ */
|
||||
|
||||
static void app_on_key(int keycode, int is_down)
|
||||
{
|
||||
(void)keycode; (void)is_down; /* 物理键系统语义;App 不映射(§3.4.1) */
|
||||
}
|
||||
|
||||
static void app_on_tap(int x, int y)
|
||||
{
|
||||
if (login_is_active()) { login_on_tap(x, y); return; }
|
||||
if (player_is_active()) { player_on_tap(x, y); return; }
|
||||
if (settings_is_active()) { settings_on_tap(x, y); return; }
|
||||
if (playlist_is_active()) { playlist_on_tap(x, y); return; }
|
||||
home_on_tap(x, y);
|
||||
}
|
||||
|
||||
static void app_on_swipe(int dir, int dx, int dy)
|
||||
{
|
||||
(void)dx;
|
||||
if (dir == MEOW_SWIPE_LEFT) {
|
||||
if (player_is_active()) { meow_view_page_pop(); return; }
|
||||
if (settings_is_active()) { meow_view_page_pop(); return; }
|
||||
if (playlist_is_active()) { meow_view_page_pop(); return; }
|
||||
/* home / login = 根 → 退出 */
|
||||
meow_log(MEOW_LOG_INFO, "exit:swipe");
|
||||
meow_ui_request_exit();
|
||||
return;
|
||||
}
|
||||
if (home_is_active()) { home_swipe(dir, dy); return; }
|
||||
if (playlist_is_active()) { playlist_swipe(dir, dy); return; }
|
||||
if (player_is_active()) { player_on_swipe(dir, dy); return; }
|
||||
}
|
||||
|
||||
static void app_on_touch_down(int x, int y)
|
||||
{
|
||||
if (home_is_active()) home_touch_down(x, y);
|
||||
else if (playlist_is_active()) playlist_touch_down(x, y);
|
||||
else if (settings_is_active()) settings_touch_down(x, y);
|
||||
}
|
||||
|
||||
static void app_on_touch_move(int x, int y)
|
||||
{
|
||||
if (home_is_active()) home_touch_move(x, y);
|
||||
else if (playlist_is_active()) playlist_touch_move(x, y);
|
||||
else if (settings_is_active()) settings_touch_move(x, y);
|
||||
}
|
||||
|
||||
static void app_on_swipe_progress(int x_start, int dx)
|
||||
{
|
||||
meow_ui_swipe_hint(x_start + dx);
|
||||
}
|
||||
|
||||
static void app_on_tick(void)
|
||||
{
|
||||
uint64_t now = meow_ui_time_ms();
|
||||
if (login_is_active()) { login_tick(now); return; }
|
||||
if (player_is_active()) { player_tick(now); return; }
|
||||
chrome_tick();
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
/* main */
|
||||
/* ============================================================ */
|
||||
int main(void)
|
||||
{
|
||||
meow_log(MEOW_LOG_INFO, "start");
|
||||
meow_ui_opts o = { APP_W, APP_H };
|
||||
if (meow_ui_init(&o) != 0) { meow_log(MEOW_LOG_ERROR, "init failed"); return 1; }
|
||||
meow_theme_add_listener(NULL);
|
||||
signal(SIGTERM, on_sigterm);
|
||||
|
||||
/* 应用数据/核心库上下文(cookie/deviceId/cache/设置) */
|
||||
appstate_init();
|
||||
|
||||
/* 播放 + 媒体会话线程(UI 不卡;无 launcher socket 时 ipc 优雅跳过) */
|
||||
player_manager_start();
|
||||
ipc_media_start();
|
||||
g_net_ready = 1;
|
||||
|
||||
/* 建五页 view */
|
||||
g_login_view = login_view_create();
|
||||
g_home_view = home_view_create();
|
||||
g_pl_view = playlist_view_create();
|
||||
g_plr_view = player_view_create();
|
||||
g_set_view = settings_view_create();
|
||||
|
||||
/* 进入根页:已登录→home,否则→login */
|
||||
meow_view_page_push(g_st.logged_in ? ACT_HOME : ACT_LOGIN);
|
||||
|
||||
meow_ui_events ev = {
|
||||
app_on_key, app_on_tap, app_on_swipe, app_on_tick, app_on_swipe_progress,
|
||||
app_on_touch_down, app_on_touch_move,
|
||||
};
|
||||
meow_ui_run(&ev);
|
||||
|
||||
/* 清理:停线程 → 释放页 */
|
||||
g_app_quit = 1;
|
||||
player_manager_stop_thread();
|
||||
ipc_media_stop();
|
||||
meow_view_free(g_set_view);
|
||||
meow_view_free(g_plr_view);
|
||||
meow_view_free(g_pl_view);
|
||||
meow_view_free(g_home_view);
|
||||
meow_view_free(g_login_view);
|
||||
meow_ui_shutdown();
|
||||
meow_log(MEOW_LOG_INFO, "exit");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user