Files
MeowOS-For-R3P2/patch_v2/ncm_app/app/ui/home.c
T

221 lines
7.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ui/home.c — 我的歌单页(ACT_HOME,根页)。
*
* 内容区用 SDK 结构化列表(meow_listview,§5.5 W_LISTVIEW)虚拟化渲染
* 「图标(folder 占位) + 歌单名 + 曲目数副标题 + 右侧箭头」。行数据源逐行填 meow_list_item;
* 滚动/选中/命中由 SDK 收口。空态/错误/底部信息行用 meow_draw_custom_register 注册非控件绘制物。
* 左缘返回 = 退出 App(app.c 处理)。下拉刷新可选:用 topbar 「↻」 动作项。
*/
#include "../ncm_app_internal.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct { meow_view *view; int active; } home_ctrl;
static home_ctrl g_hc;
static meow_widget *g_tb;
static meow_widget *g_list;
static ncm_rect_t r_cont, r_list;
static int g_empty_id, g_footer_id;
static char g_title[128];
static int g_load_err; /* 0=ok;负=错误码 */
static int g_press_row, g_press_delta, g_dragging, g_drag_last_y;
static void home_drag_reset(void)
{
g_press_row = -1;
g_press_delta = 0;
g_dragging = 0;
g_drag_last_y = 0;
}
static int home_src2(int idx, meow_list_item *out, void *ctx)
{
(void)ctx;
if (idx < 0 || idx >= g_st.playlist_count) return 0;
ncm_playlist_t *pl = &g_st.playlists[idx];
static char title[128]; /* 歌单名截断 */
static char sub[64];
snprintf(title, sizeof title, "%s", pl->name);
snprintf(sub, sizeof sub, "%d tracks", pl->track_count);
out->icon_kind = MEOW_LIST_ICON_FOLDER;
out->title = title;
out->subtitle = sub;
out->right = MEOW_LIST_RIGHT_ARROW;
out->on = 0;
out->enabled = 1;
return 1;
}
static void home_draw_empty(void *ctx)
{
(void)ctx;
if (meow_ui_activity_active() != ACT_HOME) return;
if (g_load_err == 0 && g_st.playlist_count != 0) return;
if (g_st.logged_in == 0)
ncm_draw_empty(r_list, "NOT SIGNED IN", "sign in first");
else if (g_load_err == NCM_ERR_AUTH)
ncm_draw_empty(r_list, "SESSION EXPIRED", "please sign in again");
else if (g_load_err)
ncm_draw_empty(r_list, "NETWORK ERROR", "pull to retry");
else
ncm_draw_empty(r_list, "NO PLAYLISTS", "nothing here yet");
}
static void home_draw_footer(void *ctx)
{
(void)ctx;
if (meow_ui_activity_active() != ACT_HOME) return;
if (g_load_err != 0) return;
char foot[96];
if (g_st.playlist_count == 0)
snprintf(foot, sizeof foot, "0 playlists");
else
snprintf(foot, sizeof foot, "%d playlists %s", g_st.playlist_count,
g_st.nickname[0] ? g_st.nickname : "");
ncm_draw_footer(r_cont, foot);
}
void home_reload(void)
{
g_load_err = 0;
int rc = 0;
if (g_host_mock) { /* 宿主/测试:跳过网络,用预置数据 */
rc = 0;
} else if (!g_st.logged_in) rc = NCM_ERR_AUTH;
else rc = appstate_load_playlists();
g_load_err = rc;
if (g_load_err != 0) g_st.playlist_count = 0;
if (g_list) {
meow_listview_set_count(g_list, g_st.playlist_count);
meow_listview_set_scroll(g_list, 0);
meow_listview_set_sel(g_list, -1);
}
const char *name = g_st.nickname[0] ? g_st.nickname : "My Playlists";
snprintf(g_title, sizeof g_title, "%s", name);
if (g_tb) meow_topappbar_set_title(g_tb, g_title);
const meow_theme *th = meow_theme_get();
meow_ui_set_page_bg(th->bg);
meow_ui_paint_full();
}
int home_is_active(void) { return g_hc.active; }
int home_on_tap(int x, int y)
{
if (g_tb) {
int ah = meow_topappbar_hit(g_tb, x, y);
if (ah == MEOW_TOPBAR_BACK) { home_drag_reset(); return 1; }
if (ah >= 0) { home_drag_reset(); home_reload(); return 1; } /* ↻ 刷新 */
}
if (g_load_err != 0 || g_st.playlist_count == 0) return 0;
if (meow_widget_hit(g_list, x, y)) {
int row = meow_listview_hit(g_list, x, y);
if (row < 0) { home_drag_reset(); return 1; }
home_drag_reset();
playlist_open(row);
return 1;
}
return 0;
}
void home_touch_down(int x, int y)
{
home_drag_reset();
if (g_load_err != 0 || g_st.playlist_count == 0) return;
if (meow_widget_hit(g_list, x, y)) {
int row = meow_listview_hit(g_list, x, y);
if (row >= 0) {
g_press_row = row;
meow_listview_set_sel(g_list, row);
}
g_dragging = 1;
g_drag_last_y = y;
meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h);
}
}
void home_touch_move(int x, int y)
{
(void)x;
if (!g_dragging) return;
if (g_press_row >= 0) {
int d = y - g_drag_last_y; if (d < 0) d = -d;
g_press_delta += d;
if (g_press_delta > 10) { g_press_row = -1; meow_listview_set_sel(g_list, -1); }
}
int dy = y - g_drag_last_y; g_drag_last_y = y;
if (dy == 0) return;
int before = meow_listview_scroll(g_list);
meow_listview_scroll_by(g_list, -dy);
if (meow_listview_scroll(g_list) != before)
meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h);
}
void home_swipe(int dir, int dist)
{
if (dir != MEOW_SWIPE_UP && dir != MEOW_SWIPE_DOWN) return;
if (g_load_err != 0 || g_st.playlist_count == 0) return;
int del = (dir == MEOW_SWIPE_UP) ? dist : -dist;
int before = meow_listview_scroll(g_list);
meow_listview_scroll_by(g_list, del);
if (meow_listview_scroll(g_list) != before)
meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h);
}
/* 生命周期 */
static void home_page_create(meow_view *v, void *ctx)
{
(void)v;
((home_ctrl *)ctx)->view = v;
r_cont = ncm_content_rect();
r_list = NR(r_cont.x, r_cont.y, r_cont.w, r_cont.h - APP_FOOTER_H);
if (r_list.h < 0) r_list.h = 0;
meow_ui_activity_push(ACT_HOME); /* 让下面控件 owner=ACT_HOME(§6.1 ①) */
g_tb = ncm_topbar_create("My Playlists", 0, "\xe2\x86\xbb"); /* 无返回;右侧 ↻ */
g_list = meow_listview_create(r_list.x, r_list.y, r_list.w, r_list.h, 0,
home_src2, NULL, MEOW_LIST_SEL_SINGLE);
meow_listview_set_item_h(g_list, APP_ROW_H);
meow_ui_activity_pop();
g_empty_id = meow_draw_custom_register(1, r_list.x, r_list.y, r_list.w, r_list.h,
home_draw_empty, NULL);
g_footer_id = meow_draw_custom_register(1, r_cont.x, r_cont.y + r_cont.h - APP_FOOTER_H,
r_cont.w, APP_FOOTER_H, home_draw_footer, NULL);
home_drag_reset();
}
static void home_page_enter(meow_view *v, void *ctx)
{
(void)v;
((home_ctrl *)ctx)->active = 1;
const meow_theme *th = meow_theme_get();
meow_ui_set_page_bg(th->bg);
home_reload();
}
static void home_page_leave(meow_view *v, void *ctx)
{
(void)v;
((home_ctrl *)ctx)->active = 0;
}
static void home_page_destroy(meow_view *v, void *ctx)
{
(void)v; (void)ctx;
if (g_empty_id) { meow_draw_unregister(g_empty_id); g_empty_id = 0; }
if (g_footer_id) { meow_draw_unregister(g_footer_id); g_footer_id = 0; }
if (g_list) { meow_widget_free(g_list); g_list = NULL; }
if (g_tb) { meow_widget_free(g_tb); g_tb = NULL; }
}
meow_view *home_view_create(void)
{
static const meow_view_hooks h = {
.on_create = home_page_create,
.on_enter = home_page_enter,
.on_leave = home_page_leave,
.on_destroy = home_page_destroy,
};
return meow_view_create(ACT_HOME, MEOW_VIEW_ACTIVITY, &h, &g_hc);
}