feat(ncm): 断网保持登录态 + 离线模式(可见提示/缓存可播/联网自动回在线)(M9)
用户报告:「一断网就退出到扫码登录界面,不会保持账号态切离线,缓存列表形同虚设」。 上一条已把失败分成 NETWORK/AUTH;本条把结论落到 App 状态与 UI。 - 会话状态机(appstate.c):只有 NCM_ERR_AUTH(401/403/301/302)清 cookie;网络类失败 (不可达/超时/TLS/5xx/-460)只置 g_st.offline,账号态与 session.enc 一律保留; appstate_ensure_uid 同语义(原先任何 AUTH 都清 cookie,网络故障不得进入该分支)。 - 启动(app.c):根页改由 ncm_session_boot_decide 决定——有本地会话就进 home(无网也是), 只有无本地会话才进扫码;打印 boot 决策日志。 - 离线 UX:首页个人卡「离线模式」红标 + 页脚提示 + 空态「离线模式/可播放已缓存」; 歌单页/搜索页/播放页/缓存页分别给出离线文案(缓存页点播照旧走 NCM_QUEUE_CACHE,本地可播)。 - 恢复:home 可见时每 30s 静默重试一次(强制绕过接口缓存,成功即回在线并重绘); 任何真实网络成功(home/playlist worker)也会清离线态。 - 防误判:接口缓存命中(120s 旧响应)不算「回在线」——home_worker 用 ncm_apicache_hits() 差分识别,避免离线提示被缓存命中闪掉。
This commit is contained in:
1 parent
8557da6fca
commit
707bbd8a02
8 files changed
+111
-10
No files matched your search
@@ -242,8 +242,15 @@ int main(void)
|
|||||||
g_cache_view = cache_view_create(); /* M5 已缓存列表页 */
|
g_cache_view = cache_view_create(); /* M5 已缓存列表页 */
|
||||||
mini_bar_init(); /* mini 播放栏:登记跨 Activity 绘制物(进 root 页前,首帧即参与重画) */
|
mini_bar_init(); /* mini 播放栏:登记跨 Activity 绘制物(进 root 页前,首帧即参与重画) */
|
||||||
|
|
||||||
/* 进入根页:已登录→home,否则→login */
|
/* 进入根页(M9 启动决策):本地有会话就先信它——无网也进 home(缓存可看可播),
|
||||||
meow_view_page_push(g_st.logged_in ? ACT_HOME : ACT_LOGIN);
|
* 只有「无本地会话」才进扫码页。网络类失败在首个请求后由 appstate_session_gate
|
||||||
|
* 切离线模式,不再把「连不上」当登录过期。 */
|
||||||
|
{
|
||||||
|
ncm_gate_t boot = ncm_session_boot_decide(g_st.logged_in, NCM_OK);
|
||||||
|
meow_log(MEOW_LOG_INFO, "boot: session gate=%s (cookie=%d uid=%s)",
|
||||||
|
ncm_gate_name(boot), g_st.logged_in, g_st.uid[0] ? g_st.uid : "-");
|
||||||
|
meow_view_page_push(boot == NCM_GATE_RELOGIN ? ACT_LOGIN : ACT_HOME);
|
||||||
|
}
|
||||||
|
|
||||||
meow_ui_events ev = {
|
meow_ui_events ev = {
|
||||||
app_on_key, app_on_tap, app_on_swipe, app_on_tick, app_on_swipe_progress,
|
app_on_key, app_on_tap, app_on_swipe, app_on_tick, app_on_swipe_progress,
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ int appstate_init(void)
|
|||||||
|
|
||||||
appstate_load_settings();
|
appstate_load_settings();
|
||||||
g_st.logged_in = (g_st.ctx.cookie[0] != 0);
|
g_st.logged_in = (g_st.ctx.cookie[0] != 0);
|
||||||
|
g_st.offline = 0; /* M9:启动先按在线渲染;首个网络动作失败再进离线(本地会话不被否决) */
|
||||||
g_st.active_playlist = -1;
|
g_st.active_playlist = -1;
|
||||||
g_st.playing_song = -1;
|
g_st.playing_song = -1;
|
||||||
g_st.qr_size = 0;
|
g_st.qr_size = 0;
|
||||||
@@ -169,6 +170,33 @@ void appstate_set_logged_in(const char *uid, const char *nickname)
|
|||||||
g_st.logged_in = 1;
|
g_st.logged_in = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- 会话保持 / 离线模式(M9)----
|
||||||
|
* 判定本身在 core(ncm_gate_decide,宿主可单测);这里只把结果落到 App 状态并打日志。
|
||||||
|
* 关键不变量:**只有 NCM_ERR_AUTH 会走退出登录**;传输层/服务端暂不可用只切离线,
|
||||||
|
* 绝不清 cookie(清 cookie 才是「退到扫码登录」的实质)。 */
|
||||||
|
void appstate_offline_set(int on)
|
||||||
|
{
|
||||||
|
int v = on ? 1 : 0;
|
||||||
|
if (g_st.offline == v) return;
|
||||||
|
g_st.offline = v;
|
||||||
|
meow_log(v ? MEOW_LOG_WARN : MEOW_LOG_INFO, "session: %s", v ? "offline" : "online");
|
||||||
|
}
|
||||||
|
|
||||||
|
int appstate_is_offline(void) { return g_st.offline; }
|
||||||
|
|
||||||
|
int appstate_session_gate(int rc)
|
||||||
|
{
|
||||||
|
ncm_gate_t g = ncm_gate_decide(g_st.logged_in, rc);
|
||||||
|
switch (g) {
|
||||||
|
case NCM_GATE_ONLINE: appstate_offline_set(0); break;
|
||||||
|
case NCM_GATE_OFFLINE: appstate_offline_set(1); break;
|
||||||
|
/* RELOGIN:登录态处置由调用方(app.c tick / settings 登出)执行;
|
||||||
|
* HOLD:解析/参数类错误,保持现状。 */
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return (int)g;
|
||||||
|
}
|
||||||
|
|
||||||
void appstate_logout(void)
|
void appstate_logout(void)
|
||||||
{
|
{
|
||||||
ncm_ctx_clear_cookie(&g_st.ctx);
|
ncm_ctx_clear_cookie(&g_st.ctx);
|
||||||
@@ -176,6 +204,7 @@ void appstate_logout(void)
|
|||||||
* 被下一账号复用;盘缓存目录一并清)。 */
|
* 被下一账号复用;盘缓存目录一并清)。 */
|
||||||
ncm_apicache_clear();
|
ncm_apicache_clear();
|
||||||
g_st.logged_in = 0;
|
g_st.logged_in = 0;
|
||||||
|
g_st.offline = 0;
|
||||||
g_st.uid[0] = 0;
|
g_st.uid[0] = 0;
|
||||||
g_st.nickname[0] = 0;
|
g_st.nickname[0] = 0;
|
||||||
g_st.vip = NCM_VIP_NONE; /* §20:登出清会员态(下一账号不继承) */
|
g_st.vip = NCM_VIP_NONE; /* §20:登出清会员态(下一账号不继承) */
|
||||||
@@ -199,7 +228,9 @@ void appstate_logout(void)
|
|||||||
cover_cache_reset();
|
cover_cache_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 若 uid 缺失(cookie 在但没存 uid),用 login_status_check 校验并取回。返回 0=成功。 */
|
/* 若 uid 缺失(cookie 在但没存 uid),用 login_status_check 校验并取回。返回 0=成功。
|
||||||
|
* M9:只有服务端**明确**否定会话(NCM_ERR_AUTH:HTTP 401/403、业务码 301/302)才清 cookie;
|
||||||
|
* 网络不可达/超时/服务端 5xx 一律保留 cookie 与登录态,只切离线模式。 */
|
||||||
int appstate_ensure_uid(void)
|
int appstate_ensure_uid(void)
|
||||||
{
|
{
|
||||||
if (!g_st.logged_in || !g_st.ctx.cookie[0]) return NCM_ERR_AUTH;
|
if (!g_st.logged_in || !g_st.ctx.cookie[0]) return NCM_ERR_AUTH;
|
||||||
@@ -209,12 +240,16 @@ int appstate_ensure_uid(void)
|
|||||||
nick, sizeof nick);
|
nick, sizeof nick);
|
||||||
if (rc == NCM_OK) {
|
if (rc == NCM_OK) {
|
||||||
appstate_set_logged_in(uid, nick);
|
appstate_set_logged_in(uid, nick);
|
||||||
|
appstate_offline_set(0);
|
||||||
return NCM_OK;
|
return NCM_OK;
|
||||||
}
|
}
|
||||||
/* 会话失效:清 cookie → 未登录 */
|
|
||||||
if (rc == NCM_ERR_AUTH) {
|
if (rc == NCM_ERR_AUTH) {
|
||||||
|
/* 会话确失效:清 cookie → 未登录(原逻辑) */
|
||||||
ncm_ctx_clear_cookie(&g_st.ctx);
|
ncm_ctx_clear_cookie(&g_st.ctx);
|
||||||
g_st.logged_in = 0;
|
g_st.logged_in = 0;
|
||||||
|
g_st.offline = 0;
|
||||||
|
} else if (ncm_err_is_network(rc)) {
|
||||||
|
appstate_offline_set(1); /* 只是连不上:保留账号态,离线可看缓存 */
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,6 +205,10 @@ typedef struct ncm_app_state {
|
|||||||
int qr_size;
|
int qr_size;
|
||||||
int login_state; /* NCM_LOGIN_* */
|
int login_state; /* NCM_LOGIN_* */
|
||||||
int logged_in;
|
int logged_in;
|
||||||
|
/* 离线模式(M9):网络类失败(不可达/超时/DNS/连接失败/服务端 5xx)时为 1——账号态与
|
||||||
|
* cookie 一律保留,UI 显示可见提示、已缓存列表照常可开可播;任何一次请求成功即回 0。
|
||||||
|
* 鉴权失败(NCM_ERR_AUTH)不走这里:沿用原退出登录→扫码逻辑。 */
|
||||||
|
int offline;
|
||||||
|
|
||||||
/* 账号 */
|
/* 账号 */
|
||||||
char uid[32];
|
char uid[32];
|
||||||
@@ -433,6 +437,15 @@ void appstate_save_settings(void);
|
|||||||
void appstate_set_logged_in(const char *uid, const char *nickname);
|
void appstate_set_logged_in(const char *uid, const char *nickname);
|
||||||
void appstate_logout(void);
|
void appstate_logout(void);
|
||||||
int appstate_ensure_uid(void); /* 若 uid 缺失则 login_status_check 取回;0=成功 */
|
int appstate_ensure_uid(void); /* 若 uid 缺失则 login_status_check 取回;0=成功 */
|
||||||
|
|
||||||
|
/* ---- 会话保持 / 离线模式(M9)----
|
||||||
|
* 一次网络动作的返回码 → 会话状态机(core ncm_session.h 的纯判定在上,这里落到 App 状态):
|
||||||
|
* 成功 → 在线(解除离线);网络类失败 → 离线(保留登录态/cookie);
|
||||||
|
* 鉴权失败 → 由调用方沿用原退出登录逻辑(本函数不改登录态);其它 → 保持现状。
|
||||||
|
* 返回 ncm_gate_t。可在 worker 线程调用(只写 g_st.offline,值域 0/1 幂等)。 */
|
||||||
|
int appstate_session_gate(int rc);
|
||||||
|
int appstate_is_offline(void); /* 1=离线模式(UI 画「离线模式」提示) */
|
||||||
|
void appstate_offline_set(int on); /* 直接置离线态(登出/初始化清零) */
|
||||||
int appstate_load_playlists(void); /* 拉我的歌单 */
|
int appstate_load_playlists(void); /* 拉我的歌单 */
|
||||||
int appstate_load_playlist_songs(int idx); /* 兼容:载索引 + 首个窗口(内部走 ensure) */
|
int appstate_load_playlist_songs(int idx); /* 兼容:载索引 + 首个窗口(内部走 ensure) */
|
||||||
int appstate_load_playlist_songs_page(int idx, int offset, int limit);
|
int appstate_load_playlist_songs_page(int idx, int offset, int limit);
|
||||||
|
|||||||
@@ -161,9 +161,10 @@ static void c_draw_footer(void *ctx)
|
|||||||
ncm_cache_item_t it;
|
ncm_cache_item_t it;
|
||||||
for (int i = 0; i < n; i++)
|
for (int i = 0; i < n; i++)
|
||||||
if (appstate_cache_item(i, &it) == NCM_OK) total += it.size;
|
if (appstate_cache_item(i, &it) == NCM_OK) total += it.size;
|
||||||
char sz[24], foot[96];
|
char sz[24], foot[128];
|
||||||
fmt_size(total, sz, sizeof sz);
|
fmt_size(total, sz, sizeof sz);
|
||||||
snprintf(foot, sizeof foot, "%d 首 · 合计 %s", n, sz);
|
snprintf(foot, sizeof foot, "%d 首 · 合计 %s%s", n, sz,
|
||||||
|
appstate_is_offline() ? " · 离线模式(可播放)" : "");
|
||||||
ncm_draw_footer(r_cont, foot);
|
ncm_draw_footer(r_cont, foot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -146,6 +146,21 @@ static void home_draw(void *ctx)
|
|||||||
}
|
}
|
||||||
meow_ui_text_right(pc.x + pc.w - 16, pc.y + (pc.h - 28) / 2, ">", 28, th->onSurfaceVariant);
|
meow_ui_text_right(pc.x + pc.w - 16, pc.y + (pc.h - 28) / 2, ">", 28, th->onSurfaceVariant);
|
||||||
|
|
||||||
|
/* M9 离线模式:个人卡右侧可见提示(红点 + 红字,避开「>」)。断网不再退扫码,
|
||||||
|
* 用户能从这一处看出「当前是离线,缓存照常可播」。 */
|
||||||
|
if (appstate_is_offline()) {
|
||||||
|
const char *ol = "离线模式";
|
||||||
|
int osz = th->font_body - 2;
|
||||||
|
if (osz < 16) osz = 16;
|
||||||
|
int ow = meow_ui_text_width(ol, osz);
|
||||||
|
int ox = pc.x + pc.w - 28 - ow;
|
||||||
|
int oy = pc.y + (pc.h - osz) / 2;
|
||||||
|
if (ox > pc.x + asz + 28) {
|
||||||
|
meow_ui_fill_rect(ox - 14, oy + osz / 2 - 3, 6, 6, pa->red);
|
||||||
|
meow_ui_text(ox, oy, ol, osz, pa->red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* 双页签(g_tabs=meow_tabbar widget 建)——红下划线/红选中字叠层。 */
|
/* 双页签(g_tabs=meow_tabbar widget 建)——红下划线/红选中字叠层。 */
|
||||||
if (g_tabs) {
|
if (g_tabs) {
|
||||||
int iw = r_tabs.w / 2;
|
int iw = r_tabs.w / 2;
|
||||||
@@ -201,6 +216,8 @@ static void home_draw_empty(void *ctx)
|
|||||||
if (g_home_loading) { ncm_draw_empty(r_list, "LOADING", "正在加载歌单..."); return; }
|
if (g_home_loading) { ncm_draw_empty(r_list, "LOADING", "正在加载歌单..."); return; }
|
||||||
if (g_st.logged_in == 0) ncm_draw_empty(r_list, "NOT SIGNED IN", "请先登录");
|
if (g_st.logged_in == 0) ncm_draw_empty(r_list, "NOT SIGNED IN", "请先登录");
|
||||||
else if (g_load_err == NCM_ERR_AUTH) ncm_draw_empty(r_list, "SESSION EXPIRED", "请重新登录");
|
else if (g_load_err == NCM_ERR_AUTH) ncm_draw_empty(r_list, "SESSION EXPIRED", "请重新登录");
|
||||||
|
/* M9 离线模式:网络类失败不再是「登录过期」,提示可离线听已缓存。 */
|
||||||
|
else if (appstate_is_offline()) ncm_draw_empty(r_list, "离线模式", "网络不可用 · 可播放已缓存(顶栏「已缓存」)");
|
||||||
else if (g_load_err) ncm_draw_empty(r_list, "NETWORK ERROR", "上滑重试");
|
else if (g_load_err) ncm_draw_empty(r_list, "NETWORK ERROR", "上滑重试");
|
||||||
else ncm_draw_empty(r_list, "NO PLAYLISTS", "还没有歌单");
|
else ncm_draw_empty(r_list, "NO PLAYLISTS", "还没有歌单");
|
||||||
}
|
}
|
||||||
@@ -211,8 +228,9 @@ static void home_draw_footer(void *ctx)
|
|||||||
if (meow_ui_activity_active() != ACT_HOME) return;
|
if (meow_ui_activity_active() != ACT_HOME) return;
|
||||||
if (g_load_err != 0) return;
|
if (g_load_err != 0) return;
|
||||||
char foot[192];
|
char foot[192];
|
||||||
snprintf(foot, sizeof foot, "共 %d 个歌单 %s", g_st.playlist_count,
|
snprintf(foot, sizeof foot, "共 %d 个歌单 %s%s", g_st.playlist_count,
|
||||||
g_st.nickname[0] ? g_st.nickname : "");
|
g_st.nickname[0] ? g_st.nickname : "",
|
||||||
|
appstate_is_offline() ? " · 离线模式" : "");
|
||||||
ncm_draw_footer(r_cont, foot);
|
ncm_draw_footer(r_cont, foot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,6 +255,7 @@ static void *home_worker(void *arg)
|
|||||||
{
|
{
|
||||||
(void)arg;
|
(void)arg;
|
||||||
int rc;
|
int rc;
|
||||||
|
uint64_t hits0 = ncm_apicache_hits();
|
||||||
if (!g_st.logged_in) rc = NCM_ERR_AUTH;
|
if (!g_st.logged_in) rc = NCM_ERR_AUTH;
|
||||||
else {
|
else {
|
||||||
/* §NEW MUSIC_U 临期续期:先于歌单网络请求(后续 eapi/weapi 用新 cookie)。
|
/* §NEW MUSIC_U 临期续期:先于歌单网络请求(后续 eapi/weapi 用新 cookie)。
|
||||||
@@ -247,6 +266,10 @@ static void *home_worker(void *arg)
|
|||||||
}
|
}
|
||||||
if (rc == NCM_OK)
|
if (rc == NCM_OK)
|
||||||
account_vip_maybe_refresh(0); /* §20:超 1 天/到期后各补查一次(worker 线程,不卡 UI) */
|
account_vip_maybe_refresh(0); /* §20:超 1 天/到期后各补查一次(worker 线程,不卡 UI) */
|
||||||
|
/* M9:网络类失败→离线(保留登录态);成功→回在线。但「接口缓存命中」不算回在线——
|
||||||
|
* 离线时读到 120s 内的旧缓存同样返回 NCM_OK,不能据此清掉离线提示/重试节奏。 */
|
||||||
|
int from_cache = (rc == NCM_OK) && (ncm_apicache_hits() != hits0);
|
||||||
|
if (!from_cache) appstate_session_gate(rc);
|
||||||
pthread_mutex_lock(&g_home_mu);
|
pthread_mutex_lock(&g_home_mu);
|
||||||
g_load_err = (g_st.playlist_count > 0) ? 0 : rc; /* 有数据(缓存/已载)即不置错误态 */
|
g_load_err = (g_st.playlist_count > 0) ? 0 : rc; /* 有数据(缓存/已载)即不置错误态 */
|
||||||
g_home_loading = 0;
|
g_home_loading = 0;
|
||||||
@@ -276,7 +299,20 @@ void home_reload(void)
|
|||||||
|
|
||||||
void home_tick(uint64_t now)
|
void home_tick(uint64_t now)
|
||||||
{
|
{
|
||||||
(void)now;
|
/* M9 离线恢复:离线时每 30s 静默重试一次(home worker 单飞;成功后 appstate_session_gate
|
||||||
|
* 自动回在线并重绘)。仅在 home 可见时轮询,不轰炸服务端(风控纪律)。 */
|
||||||
|
static uint64_t g_offline_retry_ms;
|
||||||
|
if (appstate_is_offline() && !g_host_mock) {
|
||||||
|
if (!g_home_thr_on && (!g_offline_retry_ms || now - g_offline_retry_ms >= 30000)) {
|
||||||
|
g_offline_retry_ms = now;
|
||||||
|
meow_log(MEOW_LOG_INFO, "home: offline retry");
|
||||||
|
ncm_api_cache_refresh_path("/api/user/playlist"); /* 离线恢复探测必须真打网络 */
|
||||||
|
home_reload();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g_offline_retry_ms = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!g_home_thr_on) return;
|
if (!g_home_thr_on) return;
|
||||||
if (g_home_gen == g_home_acked) return;
|
if (g_home_gen == g_home_acked) return;
|
||||||
g_home_acked = g_home_gen;
|
g_home_acked = g_home_gen;
|
||||||
|
|||||||
@@ -422,10 +422,13 @@ static void plr_draw_cover_dyn(void *ctx)
|
|||||||
|
|
||||||
/* 缓冲/错误态(沿用 §18 三态;错误时用文案替代时间行) */
|
/* 缓冲/错误态(沿用 §18 三态;错误时用文案替代时间行) */
|
||||||
if (perr != 0) {
|
if (perr != 0) {
|
||||||
|
/* M9:网络类失败(不可达/超时/5xx)提示离线可播缓存,而不是「登录过期」。 */
|
||||||
|
int pnet = ncm_err_is_network(perr);
|
||||||
const char *em = (perr == NCM_ERR_VIP) ? "VIP 专享,开通会员后可播放"
|
const char *em = (perr == NCM_ERR_VIP) ? "VIP 专享,开通会员后可播放"
|
||||||
: (perr == NCM_ERR_NOTFOUND) ? "无法播放:无音源(VIP/版权)"
|
: (perr == NCM_ERR_NOTFOUND) ? "无法播放:无音源(VIP/版权)"
|
||||||
: (perr == NCM_ERR_AUTH) ? "登录已过期,请重新登录"
|
: (perr == NCM_ERR_AUTH) ? "登录已过期,请重新登录"
|
||||||
: "加载失败,请检查网络";
|
: pnet ? "离线模式:网络不可用,可播放已缓存"
|
||||||
|
: "加载失败,请重试";
|
||||||
meow_ui_text_center(W / 2, g_times_y - 8, em, 20, pa->red_lit);
|
meow_ui_text_center(W / 2, g_times_y - 8, em, 20, pa->red_lit);
|
||||||
meow_ui_text_center(W / 2, g_times_y + 18, "点播放键重试 / 切下一首", 18, PLR_TEXT_DIM);
|
meow_ui_text_center(W / 2, g_times_y + 18, "点播放键重试 / 切下一首", 18, PLR_TEXT_DIM);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -225,6 +225,7 @@ static void pl_draw_empty(void *ctx)
|
|||||||
if (g_load_err == 0 && g_st.track_ids_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_plloading) { ncm_draw_empty(r_list, "加载中", "正在加载曲目..."); return; }
|
||||||
if (g_load_err == NCM_ERR_AUTH) ncm_draw_empty(r_list, "登录已过期", "请重新登录");
|
if (g_load_err == NCM_ERR_AUTH) ncm_draw_empty(r_list, "登录已过期", "请重新登录");
|
||||||
|
else if (appstate_is_offline()) ncm_draw_empty(r_list, "离线模式", "网络不可用 · 可播放已缓存(返回首页→「已缓存」)");
|
||||||
else if (g_load_err) ncm_draw_empty(r_list, "加载失败", "点按重试");
|
else if (g_load_err) ncm_draw_empty(r_list, "加载失败", "点按重试");
|
||||||
else ncm_draw_empty(r_list, "暂无歌曲", "这个歌单是空的");
|
else ncm_draw_empty(r_list, "暂无歌曲", "这个歌单是空的");
|
||||||
}
|
}
|
||||||
@@ -278,6 +279,7 @@ static void *playlist_worker(void *arg)
|
|||||||
pthread_mutex_unlock(&g_plmu);
|
pthread_mutex_unlock(&g_plmu);
|
||||||
int cur_active = g_st.active_playlist; /* ensure 路径结束校验用(当前目标) */
|
int cur_active = g_st.active_playlist; /* ensure 路径结束校验用(当前目标) */
|
||||||
int rc;
|
int rc;
|
||||||
|
int gate_rc = NCM_ERR_STALE; /* M9:首屏结果→会话/离线态(锁外应用) */
|
||||||
if (g_host_mock) rc = 0;
|
if (g_host_mock) rc = 0;
|
||||||
else if (first) {
|
else if (first) {
|
||||||
/* 首屏:快照式加载(detail 全量 trackIds + 物化第 0 页)。ctx 校验代次/目标,过期自动丢弃。
|
/* 首屏:快照式加载(detail 全量 trackIds + 物化第 0 页)。ctx 校验代次/目标,过期自动丢弃。
|
||||||
@@ -312,6 +314,8 @@ static void *playlist_worker(void *arg)
|
|||||||
} else {
|
} else {
|
||||||
g_load_err = rc; /* 索引失败/鉴权失败 → 整页空态(点按重试) */
|
g_load_err = rc; /* 索引失败/鉴权失败 → 整页空态(点按重试) */
|
||||||
}
|
}
|
||||||
|
/* M9:本次首屏结果同步会话/离线态(网络类→离线提示;成功→回在线;STALE 不采纳)。 */
|
||||||
|
gate_rc = rc;
|
||||||
g_plloaded_idx = tidx;
|
g_plloaded_idx = tidx;
|
||||||
g_plloaded_gen = tgen;
|
g_plloaded_gen = tgen;
|
||||||
/* §NEW bug B:首屏发布后标记窗口归属=目标歌单(失败/部分也归属,支持同歌单重试不清窗)。
|
/* §NEW bug B:首屏发布后标记窗口归属=目标歌单(失败/部分也归属,支持同歌单重试不清窗)。
|
||||||
@@ -326,6 +330,7 @@ static void *playlist_worker(void *arg)
|
|||||||
g_plloading = 0;
|
g_plloading = 0;
|
||||||
g_plgen++;
|
g_plgen++;
|
||||||
pthread_mutex_unlock(&g_plmu);
|
pthread_mutex_unlock(&g_plmu);
|
||||||
|
if (gate_rc != NCM_ERR_STALE) appstate_session_gate(gate_rc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ static void sr_draw_empty(void *ctx)
|
|||||||
if (sr_view() != SR_EMPTY) return; /* 历史/结果态有行,空态不画 */
|
if (sr_view() != SR_EMPTY) return; /* 历史/结果态有行,空态不画 */
|
||||||
if (g_loading) { ncm_draw_empty(r_list, "搜索中", "正在搜索..."); return; }
|
if (g_loading) { ncm_draw_empty(r_list, "搜索中", "正在搜索..."); return; }
|
||||||
if (g_st.search_err == NCM_ERR_AUTH) ncm_draw_empty(r_list, "登录已过期", "请重新登录");
|
if (g_st.search_err == NCM_ERR_AUTH) ncm_draw_empty(r_list, "登录已过期", "请重新登录");
|
||||||
|
else if (appstate_is_offline() && g_st.search_err) ncm_draw_empty(r_list, "离线模式", "搜索需要网络 · 可播放已缓存");
|
||||||
else if (g_st.search_err) ncm_draw_empty(r_list, "搜索失败", "点「搜索」重试");
|
else if (g_st.search_err) ncm_draw_empty(r_list, "搜索失败", "点「搜索」重试");
|
||||||
else if (!g_st.search_query[0]) ncm_draw_empty(r_list, "输入关键词", "输入后点「搜索」");
|
else if (!g_st.search_query[0]) ncm_draw_empty(r_list, "输入关键词", "输入后点「搜索」");
|
||||||
else if (!g_searched) ncm_draw_empty(r_list, "输入后点「搜索」", "或点历史记录");
|
else if (!g_searched) ncm_draw_empty(r_list, "输入后点「搜索」", "或点历史记录");
|
||||||
|
|||||||
Reference in new issue
Block a user