ncm 三期三批: 歌曲对象瘦身(1324→608B)+滑动窗口(NCM_SONG_WINDOW=256, 取消1000截断支撑任意长度歌单)+播放快照解耦 — agent-251
- core/ncm_api.h: ncm_song_t 瘦身 id24/name128/art96/al96/pic256/dt int32 (1324B→608B) - appstate.c 滑动窗口: song_ids 全量 trackIds 索引(16384) + songs[256] 窗口感知 (song_valid 位图/window_base/滑窗 memmove 保留重叠), ensure_range 批网格(100)对齐 预取, songmeta.c 盘缓存 <cache_dir>/meta/<id>.bin (回滚/二次进入 0 网络请求) - playlist.c 触底分页退役→视口 ensure(±24 行), 占位行可直点(播放线程 fetch 物化), footer 改视口区间/总数 - 播放兼容: g_play.play_song 快照(mu), run_song 起播物化后全链路(下载/歌词/IPC META/ 播放页 UI)读快照——窗口滑出当前播放曲不崩; 边界 song_count→track_ids_count - 验证(0 真实请求): pagination_sim 全 PASS(5191 无截断/52 批); window_sim 6000 首 全程下滚 750 步视口全物化/song_detail 恰 60 次/回滚+0 请求/播放 fetch 不滑窗; core 宿主+qemu 全 PASS; mipsel -Wall -Wextra 0 warning, bss 2052068→1080900(-47%) - 未部署真机(设备音频线排查中, 部署留主会话)
This commit is contained in:
1 parent
d8898afa09
commit
997f89f879
18 files changed
+987
-209
No files matched your search
@@ -25,6 +25,7 @@ static ncm_rect_t r_cont;
|
||||
static int g_custom_disc, g_custom_dyn;
|
||||
static int g_landscape;
|
||||
static int g_last_pos_ms, g_last_state, g_last_line, g_last_song;
|
||||
static char g_last_meta_id[24]; /* 已上封面的元数据 id(快照滞后 settle 时纠正封面/歌名) */
|
||||
|
||||
/* 运行期几何(player_compute_geom 填充;各带绘制物/命中共用)。 */
|
||||
static ncm_rect_t g_disc_r, g_dyn_r; /* 盘带 / 动态带 bbox(不重叠) */
|
||||
@@ -40,7 +41,16 @@ static ncm_rect_t g_lyr; /* 歌词区 */
|
||||
static int cur_song(void)
|
||||
{
|
||||
int c = player_manager_playing_song();
|
||||
return (c >= 0 && c < g_st.song_count) ? c : -1;
|
||||
return (c >= 0 && c < g_st.track_ids_count) ? c : -1;
|
||||
}
|
||||
|
||||
/* 当前播放曲元数据(§17):优先播放快照(窗口无关);快照未就绪时退窗口拷贝。 */
|
||||
static int cur_song_meta(ncm_song_t *out)
|
||||
{
|
||||
if (player_manager_current_song(out) == 0) return 0;
|
||||
int sc = cur_song();
|
||||
if (sc >= 0 && appstate_song_copy(sc, out) == 0) return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void fmt_ms(int64_t ms, char *out, size_t sz)
|
||||
@@ -188,10 +198,10 @@ static void plr_draw_dyn(void *ctx)
|
||||
if (meow_ui_activity_active() != ACT_PLAYER) return;
|
||||
const meow_theme *th = meow_theme_get();
|
||||
const ncm_pal_t *pa = ncm_palette(g_dark);
|
||||
int sc = cur_song();
|
||||
const ncm_song_t *s = (sc >= 0) ? &g_st.songs[sc] : NULL;
|
||||
const char *nm = s ? s->name : "暂无播放";
|
||||
const char *ar = s ? s->art_name : "";
|
||||
ncm_song_t sm;
|
||||
int have = (cur_song_meta(&sm) == 0);
|
||||
const char *nm = have ? sm.name : "暂无播放";
|
||||
const char *ar = have ? sm.art_name : "";
|
||||
|
||||
if (g_landscape) {
|
||||
meow_ui_text(g_info_x, g_title_y, ncm_text_fit(nm, g_info_w, 28), 28, th->onSurface);
|
||||
@@ -204,7 +214,7 @@ static void plr_draw_dyn(void *ctx)
|
||||
/* 进度条 + 时间 */
|
||||
int pos = (int)player_manager_pos_ms();
|
||||
int dur = (int)player_manager_dur_ms();
|
||||
if (dur <= 0 && sc >= 0) dur = (int)(g_st.songs[sc].duration_ms);
|
||||
if (dur <= 0 && have) dur = (int)sm.duration_ms;
|
||||
int frac = dur > 0 ? (int)((int64_t)pos * 1000 / dur) : 0;
|
||||
if (frac < 0) frac = 0; if (frac > 1000) frac = 1000;
|
||||
char lp[16], rp[16];
|
||||
@@ -302,11 +312,12 @@ void player_on_tap(int x, int y)
|
||||
|
||||
void player_play_song(int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= g_st.song_count) return;
|
||||
/* 二期:黑胶封面用真实专辑图(song_detail 的 al.picUrl,经 ncm_cache 缓存/限幅),
|
||||
* 无 al.picUrl(如无版权占位)时回落歌单封面。 */
|
||||
const ncm_song_t *s = &g_st.songs[idx];
|
||||
const char *cover = (s && s->al_pic[0]) ? s->al_pic : g_st.cover_url;
|
||||
if (idx < 0 || idx >= g_st.track_ids_count) return;
|
||||
/* 黑胶封面用真实专辑图(song_detail 的 al.picUrl,经 ncm_cache 缓存/限幅);
|
||||
* 滑窗未物化(占位行直点)时回落歌单封面,元数据由播放线程物化后快照接管(§17)。 */
|
||||
ncm_song_t s;
|
||||
const char *cover = (appstate_song_copy(idx, &s) == 0 && s.al_pic[0])
|
||||
? s.al_pic : g_st.cover_url;
|
||||
player_manager_play(idx);
|
||||
appstate_set_playing_song(idx, cover);
|
||||
cover_request(cover);
|
||||
@@ -338,13 +349,16 @@ void player_tick(uint64_t now)
|
||||
|
||||
if (sc != g_last_song) {
|
||||
g_last_song = sc;
|
||||
/* 切歌(next/prev/自动顺延)→ 请求新曲专辑封面(黑胶盘换图) */
|
||||
if (sc >= 0) {
|
||||
const ncm_song_t *s2 = &g_st.songs[sc];
|
||||
cover_request(s2->al_pic[0] ? s2->al_pic : g_st.cover_url);
|
||||
}
|
||||
meow_ui_invalidate(g_dyn_r.x, g_dyn_r.y, g_dyn_r.w, g_dyn_r.h); /* 歌名/歌手变 */
|
||||
}
|
||||
/* 元数据 id 变化(含快照滞后 settle:切歌瞬间快照仍是旧曲,play 线程更新后此处纠正)→
|
||||
* 请求新曲专辑封面(黑胶盘换图)+ 刷动态带。 */
|
||||
ncm_song_t s2;
|
||||
if (sc >= 0 && cur_song_meta(&s2) == 0 && strcmp(s2.id, g_last_meta_id) != 0) {
|
||||
ncm_strlcpy(g_last_meta_id, s2.id, sizeof g_last_meta_id);
|
||||
cover_request(s2.al_pic[0] ? s2.al_pic : g_st.cover_url);
|
||||
meow_ui_invalidate(g_dyn_r.x, g_dyn_r.y, g_dyn_r.w, g_dyn_r.h);
|
||||
}
|
||||
if (cover_changed()) {
|
||||
cover_ack();
|
||||
meow_ui_invalidate(g_disc_r.x, g_disc_r.y, g_disc_r.w, g_disc_r.h);
|
||||
@@ -376,6 +390,7 @@ static void plr_page_create(meow_view *v, void *ctx)
|
||||
g_custom_dyn = meow_draw_custom_register(11, g_dyn_r.x, g_dyn_r.y, g_dyn_r.w, g_dyn_r.h,
|
||||
plr_draw_dyn, NULL);
|
||||
g_last_pos_ms = -1; g_last_state = -1; g_last_line = -1; g_last_song = -1;
|
||||
g_last_meta_id[0] = 0;
|
||||
}
|
||||
|
||||
static void plr_page_enter(meow_view *v, void *ctx)
|
||||
|
||||
@@ -25,7 +25,9 @@ static char g_title[256];
|
||||
static volatile int g_load_err;
|
||||
static int g_press_row, g_press_delta, g_dragging, g_drag_last_y;
|
||||
|
||||
/* 歌单详情加载后台 worker(大歌单可达数十秒,不能占 UI 线程)。 */
|
||||
/* 歌单详情加载后台 worker(大歌单可达数十秒,不能占 UI 线程)。
|
||||
* §17 滑动窗口:worker 两种任务——①首屏(g_ens_first=1):重建 trackIds 索引 + 物化首段;
|
||||
* ②滑窗补载:物化视口区间 [g_ens_lo,g_ens_hi)(ensure_range,盘缓存优先)。 */
|
||||
static pthread_mutex_t g_plmu = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_t g_plthr;
|
||||
static int g_plthr_on;
|
||||
@@ -33,8 +35,9 @@ static volatile int g_plgen;
|
||||
static int g_placked;
|
||||
static volatile int g_plloading;
|
||||
static volatile int g_plloaded_idx;
|
||||
static volatile int g_ploffset; /* 本页起始下标(0=首屏重头;>0=触底追加) */
|
||||
static volatile int g_pl_more; /* 1=尚有下一页可加载(song_count < track_ids_count 且未到 NCM_SONG_MAX) */
|
||||
static volatile int g_ens_lo, g_ens_hi; /* 滑窗补载目标区间(全局下标) */
|
||||
static volatile int g_ens_first; /* 1=首屏重头(offset=0) */
|
||||
static volatile int g_ens_err; /* 最近一次滑窗补载错误(0=ok;首屏错误走 g_load_err) */
|
||||
|
||||
static void pl_drag_reset(void)
|
||||
{
|
||||
@@ -44,15 +47,24 @@ static void pl_drag_reset(void)
|
||||
static int pl_src2(int idx, meow_list_item *out, void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
if (idx < 0 || idx >= g_st.song_count) return 0;
|
||||
ncm_song_t *s = &g_st.songs[idx];
|
||||
if (idx < 0 || idx >= g_st.track_ids_count) return 0;
|
||||
static ncm_song_t s_s; /* 锁内拷贝驻留缓冲(src2 由 UI 线程串行调用,title 指针对当次绘制有效) */
|
||||
if (appstate_song_copy(idx, &s_s) != 0) {
|
||||
/* 占位行:滑窗未覆盖/未物化(后台 ensure 完成后自愈)。 */
|
||||
out->icon_kind = MEOW_LIST_ICON_NONE;
|
||||
out->title = "···";
|
||||
out->subtitle = "加载中";
|
||||
out->right = MEOW_LIST_RIGHT_ARROW;
|
||||
out->on = 0; out->enabled = 1;
|
||||
return 1;
|
||||
}
|
||||
static char sub[256];
|
||||
if (s->art_name[0] && s->album_name[0]) snprintf(sub, sizeof sub, "%s · %s", s->art_name, s->album_name);
|
||||
else if (s->art_name[0]) snprintf(sub, sizeof sub, "%s", s->art_name);
|
||||
else if (s->album_name[0]) snprintf(sub, sizeof sub, "%s", s->album_name);
|
||||
else snprintf(sub, sizeof sub, "-");
|
||||
if (s_s.art_name[0] && s_s.album_name[0]) snprintf(sub, sizeof sub, "%s · %s", s_s.art_name, s_s.album_name);
|
||||
else if (s_s.art_name[0]) snprintf(sub, sizeof sub, "%s", s_s.art_name);
|
||||
else if (s_s.album_name[0]) snprintf(sub, sizeof sub, "%s", s_s.album_name);
|
||||
else snprintf(sub, sizeof sub, "-");
|
||||
out->icon_kind = MEOW_LIST_ICON_NONE;
|
||||
out->title = s->name;
|
||||
out->title = s_s.name;
|
||||
out->subtitle = sub;
|
||||
out->right = MEOW_LIST_RIGHT_ARROW;
|
||||
out->on = 0; out->enabled = 1;
|
||||
@@ -64,12 +76,12 @@ static void pl_row_bg(void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
if (meow_ui_activity_active() != ACT_PLAYLIST) return;
|
||||
if (g_load_err != 0 || g_st.song_count == 0) return;
|
||||
if (g_load_err != 0 || g_st.track_ids_count == 0) return;
|
||||
const meow_theme *th = meow_theme_get();
|
||||
int item = APP_ROW_H;
|
||||
int off = meow_listview_scroll(g_list);
|
||||
int first = off / item, last = (off + r_list.h) / item + 1;
|
||||
if (last > g_st.song_count) last = g_st.song_count;
|
||||
if (last > g_st.track_ids_count) last = g_st.track_ids_count;
|
||||
for (int i = first; i < last; i++) {
|
||||
int ry = r_list.y + (i * item - off) + 1, th2 = item - 2;
|
||||
if (ry < r_list.y || ry + th2 > r_list.y + r_list.h) continue; /* 只画完整落在视口内的行 */
|
||||
@@ -100,7 +112,7 @@ static void pl_draw(void *ctx)
|
||||
int nmx = r_cov.x + r_cov.w + 12;
|
||||
char meta[256];
|
||||
if (pl) snprintf(meta, sizeof meta, "创建者 · %d 首", pl->track_count);
|
||||
else snprintf(meta, sizeof meta, "曲目 %d 首", g_st.song_count);
|
||||
else snprintf(meta, sizeof meta, "曲目 %d 首", g_st.track_ids_count);
|
||||
/* 歌单名(截断到卡片右缘:按 UTF-8 字符合法边界逐字累加测宽)。 */
|
||||
{
|
||||
int maxw = r_card.x + r_card.w - 16 - nmx;
|
||||
@@ -131,11 +143,11 @@ static void pl_draw(void *ctx)
|
||||
meow_ui_fill_rect(r_cmt.x + r_cmt.w / 2 + 34, r_cmt.y + 10, 6, 6, pa->red);
|
||||
|
||||
/* 曲目行:红 mini-vinyl 缩略 + 按压红条(文本由 listview z=10 画) */
|
||||
if (g_load_err == 0 && g_st.song_count > 0) {
|
||||
if (g_load_err == 0 && g_st.track_ids_count > 0) {
|
||||
int item = APP_ROW_H, isz = 24;
|
||||
int off = meow_listview_scroll(g_list);
|
||||
int first = off / item, last = (off + r_list.h) / item + 1;
|
||||
if (last > g_st.song_count) last = g_st.song_count;
|
||||
if (last > g_st.track_ids_count) last = g_st.track_ids_count;
|
||||
for (int i = first; i < last; i++) {
|
||||
int ry = r_list.y + (i * item - off) + 1, th2 = item - 2;
|
||||
if (ry < r_list.y || ry + th2 > r_list.y + r_list.h) continue;
|
||||
@@ -154,7 +166,7 @@ static void pl_draw_empty(void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
if (meow_ui_activity_active() != ACT_PLAYLIST) return;
|
||||
if (g_load_err == 0 && g_st.song_count != 0) return;
|
||||
if (g_load_err == 0 && g_st.track_ids_count != 0) return;
|
||||
if (g_plloading) { ncm_draw_empty(r_list, "加载中", "正在加载曲目..."); return; }
|
||||
if (g_load_err == NCM_ERR_AUTH) ncm_draw_empty(r_list, "登录已过期", "请重新登录");
|
||||
else if (g_load_err) ncm_draw_empty(r_list, "加载失败", "点按重试");
|
||||
@@ -166,18 +178,22 @@ static void pl_draw_footer(void *ctx)
|
||||
(void)ctx;
|
||||
if (meow_ui_activity_active() != ACT_PLAYLIST) return;
|
||||
if (g_load_err != 0) return;
|
||||
int total = (g_st.active_playlist >= 0 && g_st.active_playlist < g_st.playlist_count)
|
||||
? g_st.playlists[g_st.active_playlist].track_count : g_st.song_count;
|
||||
int total = g_st.track_ids_count;
|
||||
if (total <= 0) return;
|
||||
/* 视口位置 / 总数(滑窗模型下「已物化数」无用户意义,视口区间更直观) */
|
||||
int first = meow_listview_scroll(g_list) / APP_ROW_H + 1;
|
||||
int last = first + r_list.h / APP_ROW_H;
|
||||
if (last > total) last = total;
|
||||
char foot[96];
|
||||
snprintf(foot, sizeof foot, "%d/%d 首", g_st.song_count, total);
|
||||
snprintf(foot, sizeof foot, "%d-%d / %d 首", first, last, total);
|
||||
ncm_draw_footer(r_cont, foot);
|
||||
}
|
||||
|
||||
/* apply:reset_scroll=1 时列表回顶并清选中(首屏/刷新);0=保持当前滚动(触底追加,防跳顶)。 */
|
||||
/* apply:reset_scroll=1 时列表回顶并清选中(首屏/刷新);0=保持当前滚动(滑窗补载,防跳顶)。 */
|
||||
static void pl_apply(int reset_scroll)
|
||||
{
|
||||
if (g_list) {
|
||||
meow_listview_set_count(g_list, g_st.song_count);
|
||||
meow_listview_set_count(g_list, g_st.track_ids_count); /* 全量行数(占位行兜底未物化区) */
|
||||
if (reset_scroll) { meow_listview_set_scroll(g_list, 0); meow_listview_set_sel(g_list, -1); }
|
||||
}
|
||||
if (g_tb && g_st.active_playlist >= 0 && g_st.active_playlist < g_st.playlist_count) {
|
||||
@@ -193,16 +209,16 @@ static void *playlist_worker(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
int my_idx = g_st.active_playlist;
|
||||
int off = g_ploffset;
|
||||
int first = g_ens_first;
|
||||
int lo = g_ens_lo, hi = g_ens_hi;
|
||||
int rc;
|
||||
if (g_host_mock) rc = 0;
|
||||
else if (my_idx < 0) rc = NCM_ERR_ARG;
|
||||
else rc = appstate_load_playlist_songs_page(my_idx, off, NCM_SONG_BATCH);
|
||||
else if (first) rc = appstate_load_playlist_songs_page(my_idx, 0, NCM_SONG_BATCH);
|
||||
else rc = appstate_song_ensure_range(lo, hi);
|
||||
pthread_mutex_lock(&g_plmu);
|
||||
g_load_err = rc;
|
||||
/* 本页后仍有多余 trackIds(tail 未到)且未到内存上限 → 还有下一页;否则到屏尾。 */
|
||||
g_pl_more = (rc == NCM_OK) && (g_st.song_count < g_st.track_ids_count) &&
|
||||
(g_st.song_count < NCM_SONG_MAX);
|
||||
if (first) g_load_err = rc; /* 首屏失败 → 整页空态(点按重试) */
|
||||
else g_ens_err = rc; /* 补载失败 → snack + 占位行保留(滚动/点按再试) */
|
||||
g_plloading = 0;
|
||||
g_plloaded_idx = my_idx;
|
||||
g_plgen++;
|
||||
@@ -210,19 +226,23 @@ static void *playlist_worker(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 触底加载下一页:仅当仍有下一页、未在载、未失败、未到 NCM_SONG_MAX 时发。 */
|
||||
static void pl_maybe_load_more(void)
|
||||
/* 视口驱动滑窗补载:视口 ±24 行有未物化槽位 → 发 ensure worker(已在载/失败态/宿主 mock 不发)。 */
|
||||
static void pl_maybe_ensure(void)
|
||||
{
|
||||
if (g_plthr_on || g_host_mock) return;
|
||||
if (g_load_err != 0) return; /* 失败态:走点按重试,不自动循环 */
|
||||
if (!g_pl_more) return;
|
||||
if (g_st.song_count >= NCM_SONG_MAX) return;
|
||||
/* 视口底接近列表底(最后一行即将可见即预取) */
|
||||
int list_px = g_st.song_count * APP_ROW_H;
|
||||
int max_scroll = list_px - r_list.h;
|
||||
if (max_scroll < 0) max_scroll = 0;
|
||||
if (meow_listview_scroll(g_list) < max_scroll - APP_ROW_H * 2) return;
|
||||
g_ploffset = g_st.song_count; /* 下一页起始 = 已物化数 */
|
||||
if (g_load_err != 0) return; /* 首屏失败态:走点按重试 */
|
||||
int total = g_st.track_ids_count;
|
||||
if (total <= 0) return;
|
||||
int scroll = meow_listview_scroll(g_list);
|
||||
int first = scroll / APP_ROW_H;
|
||||
int last = (scroll + r_list.h) / APP_ROW_H + 1;
|
||||
int lo = first - 24, hi = last + 24;
|
||||
if (lo < 0) lo = 0;
|
||||
if (hi > total) hi = total;
|
||||
if (lo >= hi) return;
|
||||
if (appstate_range_loaded(lo, hi)) return; /* 已物化:无操作(窗口原地不动) */
|
||||
g_ens_lo = lo; g_ens_hi = hi;
|
||||
g_ens_first = 0;
|
||||
g_plloading = 1;
|
||||
g_plthr_on = 1;
|
||||
if (pthread_create(&g_plthr, NULL, playlist_worker, NULL) != 0) {
|
||||
@@ -232,13 +252,11 @@ static void pl_maybe_load_more(void)
|
||||
|
||||
void playlist_refresh(void)
|
||||
{
|
||||
if (g_host_mock) { g_load_err = 0; g_pl_more = 0; pl_apply(1); return; }
|
||||
if (g_host_mock) { g_load_err = 0; g_ens_err = 0; pl_apply(1); return; }
|
||||
if (g_plthr_on) return;
|
||||
g_load_err = 0;
|
||||
g_st.song_count = 0;
|
||||
g_st.track_ids_count = 0;
|
||||
g_ploffset = 0;
|
||||
g_pl_more = 0;
|
||||
g_ens_err = 0;
|
||||
g_ens_first = 1; /* 首屏:重建索引 + 物化首段 */
|
||||
g_plloading = 1;
|
||||
g_plthr_on = 1;
|
||||
if (pthread_create(&g_plthr, NULL, playlist_worker, NULL) != 0) {
|
||||
@@ -257,20 +275,15 @@ void playlist_tick(uint64_t now)
|
||||
g_plloading = 0;
|
||||
if (g_plloaded_idx != g_st.active_playlist) { playlist_refresh(); return; }
|
||||
if (g_load_err != 0) {
|
||||
if (g_ploffset == 0) {
|
||||
g_st.song_count = 0; /* 首屏失败 → 整页空态(点按重试) */
|
||||
pl_apply(1);
|
||||
} else {
|
||||
/* 追加失败 → 保留已载歌曲 + 重置 g_pl_more(触底/点击可重试) */
|
||||
ncm_snack("加载失败");
|
||||
g_load_err = 0;
|
||||
g_pl_more = (g_st.song_count < g_st.track_ids_count) &&
|
||||
(g_st.song_count < NCM_SONG_MAX);
|
||||
pl_apply(0);
|
||||
}
|
||||
g_st.track_ids_count = 0; /* 首屏失败 → 整页空态(点按重试) */
|
||||
pl_apply(1);
|
||||
return;
|
||||
}
|
||||
pl_apply(g_ploffset == 0); /* 首屏回顶;触底追加保持滚动 */
|
||||
if (g_ens_err != 0) {
|
||||
ncm_snack("加载失败");
|
||||
g_ens_err = 0; /* 占位行保留:滚动/点按触发重试 */
|
||||
}
|
||||
pl_apply(g_ens_first);
|
||||
}
|
||||
|
||||
void playlist_open(int idx)
|
||||
@@ -307,7 +320,7 @@ int playlist_on_tap(int x, int y)
|
||||
playlist_refresh();
|
||||
return 1;
|
||||
}
|
||||
if (g_st.song_count == 0) return 0; /* 空歌单(无失败):不重试 */
|
||||
if (g_st.track_ids_count == 0) return 0; /* 空歌单(无失败):不重试 */
|
||||
if (meow_widget_hit(g_list, x, y)) {
|
||||
/* 误触修复:小拖动(<SWIPE_THRESH)会先滚动列表、release 又被 SDK 判成 TAP,旧的
|
||||
* meow_listview_hit(x,y) 用“释放点 + 更新后的 scroll”命中 → 打到“已移动到手指下”的行,
|
||||
@@ -317,7 +330,7 @@ int playlist_on_tap(int x, int y)
|
||||
int row = (g_press_row >= 0) ? g_press_row : meow_listview_hit(g_list, x, y);
|
||||
pl_drag_reset();
|
||||
if (row < 0 || was_drag) return 1;
|
||||
player_play_song(row);
|
||||
player_play_song(row); /* 占位行也可点:播放线程经 appstate_song_fetch 物化该曲 */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -326,7 +339,7 @@ int playlist_on_tap(int x, int y)
|
||||
void playlist_touch_down(int x, int y)
|
||||
{
|
||||
pl_drag_reset();
|
||||
if (g_load_err != 0 || g_st.song_count == 0) return;
|
||||
if (g_load_err != 0 || g_st.track_ids_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;
|
||||
@@ -350,20 +363,20 @@ void playlist_touch_move(int x, int y)
|
||||
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);
|
||||
pl_maybe_load_more();
|
||||
pl_maybe_ensure();
|
||||
}
|
||||
}
|
||||
|
||||
void playlist_swipe(int dir, int dist)
|
||||
{
|
||||
if (dir != MEOW_SWIPE_UP && dir != MEOW_SWIPE_DOWN) return;
|
||||
if (g_load_err != 0 || g_st.song_count == 0) return;
|
||||
if (g_load_err != 0 || g_st.track_ids_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);
|
||||
pl_maybe_load_more();
|
||||
pl_maybe_ensure();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,9 @@ static void sr_apply(void)
|
||||
meow_ui_paint_full();
|
||||
}
|
||||
|
||||
/* 后台 worker:唯一网络调用(cloudsearch),UI 不卡。 */
|
||||
/* 后台 worker:唯一网络调用(cloudsearch),UI 不卡。
|
||||
* §17:结果集(≤NCM_SEARCH_MAX,远小于窗口)经 appstate_adopt_songs 收编为窗口 base=0
|
||||
* 播放上下文(song_ids/track_ids_count 同步),播放/上下一首对结果集生效。 */
|
||||
static void *search_worker(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
@@ -104,12 +106,12 @@ static void *search_worker(void *arg)
|
||||
g_st.songs, NCM_SEARCH_MAX, &n);
|
||||
pthread_mutex_lock(&g_mu);
|
||||
if (rc == NCM_OK) {
|
||||
appstate_adopt_songs(n); /* 收编 songs[0..n) 为窗口(写侧在锁内) */
|
||||
g_st.search_count = n;
|
||||
g_st.song_count = n; /* 结果集作为当前播放上下文 */
|
||||
g_st.search_err = 0;
|
||||
} else {
|
||||
appstate_adopt_songs(0);
|
||||
g_st.search_count = 0;
|
||||
g_st.song_count = 0;
|
||||
g_st.search_err = rc;
|
||||
}
|
||||
g_loading = 0;
|
||||
|
||||
Reference in new issue
Block a user