Files
MeowOS-For-R3P2/patch_v2/ncm_app/app/ui/search.c
T
AskaEth 22f9dab2ce fix(ncm): 列表首行标题不显示 — 行高按字体行高派生(M12)
根因(真机 seated,非数据/颜色/遮挡):SDK meow_listview 双行渲染把
「2*行高 + 2」的文本块在行内垂直居中,且标题只在 ty >= 视口顶时才画
(meow_ui_widget.c:2061 的越界守卫)。真机 source_han_serif 20px 面
ascent 24 + descent 6 → 行高 30 → 文本块 62px,而 ncm 行高 APP_ROW_H=56
→ ty = 行顶 - 3;首行行顶 == 视口顶 → ty < 视口顶 → 标题被整条跳过,
副标题(ty+32)仍在视口内照画。两类列表同用该路径 + 同一行高,故症状一致。

修复(不动 SDK):ncm_app_internal.h 新增 ncm_row_h()/ncm_row_h_for_line_h(),
行高 = max(56, 2*字体行高 + 2 + 8)(偶数;本机 30 → 70,卡高 62 == 文本块);
home/playlist/queue/cache/search 在 page create 取一次 g_item_h,统一用于
set_item_h 与卡片几何/可见行/页脚/补载视口换算。

回归:
- app/test/test_meow_row_text_fit.c(新):真机字库行高矩阵 14/21/26/27/30
  48 断言(文本块 ≤ 行高、首行 ty ≥ 0、卡高 ≥ 文本块、旧 56 哨兵)。
- app/test/test_first_row_title_render.c(新):--wrap 行高=30 驱动真实 SDK
  渲染 + 读回 PPM 像素计数:旧 56 → 首行标题 0 像素/副标题 186;新 70 →
  标题 84/副标题 100。
- test_meow_row_gap、plpage_sim 全 PASS;ncm_host 7 页出图与改动前逐字节相同
  (宿主行高 14 → 行高仍 56,证重构无视觉回归);5 页自检 PASS;0 warning。
- plpage_sim 临时目录改 $TMPDIR(Termux /tmp 不可写,原写死无法运行)。
- REPORT §43:根因/排除方向/修复/验证/真机验收要点。
2026-11-05 19:51:01 +08:00

524 lines
21 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/search.c — 搜索页(ACT_SEARCH,顶栏搜索按钮进入)。
*
* §23(REPORT):
* 1. 搜索历史:进页自动弹键盘(meow_textfield_activate);历史本地持久化(meow_config,
* 最近 ≤12 条、去重、最新在前);未输入时显示历史列表(点=直接搜、左滑删单条、清空全部)。
* 2. 结果分类「单曲/歌单」:顶部小页签(单曲 type=1 / 歌单 type=1000);两页签各自独立
* 结果集与滚动位置(g_scroll_song/g_scroll_pl);歌单行点击=playlist_open_pl 进详情。
* 3. 加载更多:触底分页(offset 累加,NCM_SEARCH_PAGE=30/页,cloudsearch 同参数);
* 每类各记各的 offset(appstate_search_offset 回填)。
* 4. 修 search_on_tap 误触(NCM_UI_REVIEW §3-2):套用 g_press_row + g_press_delta>10 抑制
* (对齐 home/playlist §13.3)。
* 5. 结果不再覆写歌单上下文:单曲结果写 g_st.search_songs[](独立数组,appstate 持有),
* 播放搜索单曲走 player_play_search_song(建立「搜索队列」上下文,queue_src=SEARCH),
* 原歌单窗口(g_st.songs[]/track_ids_count)不被破坏。
*
* 风控纪律(用户指定):**真实请求只在用户点「搜索」按钮/切页签/翻页时发**——进页不自动搜索,
* IME 输入仅本地编辑,不逐键发请求。调试/测试全部离线 stub(g_host_mock)。
*/
#include "../ncm_app_internal.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
typedef struct { meow_view *view; int active; } search_ctrl;
static search_ctrl g_sc;
/* 视图模式 */
enum { SR_HIST = 0, SR_RES, SR_EMPTY };
static meow_widget *g_tb, *g_field, *g_list;
static ncm_rect_t r_cont, r_list, r_btn, r_tabs[2];
static int g_empty_id, g_footer_id, g_btn_id, g_tabbar_id;
static int g_press_row, g_press_delta, g_dragging, g_drag_last_y;
static int g_scroll_song, g_scroll_pl; /* 两页签各自滚动位置(§23)*/
static int g_item_h = APP_ROW_H; /* 两行列表行高(M12:按字体行高派生,见 ncm_row_h) */
static pthread_mutex_t g_mu = PTHREAD_MUTEX_INITIALIZER;
static pthread_t g_thr;
static int g_thr_on;
static volatile int g_gen;
static int g_acked;
static volatile int g_loading;
static char g_query[256]; /* worker 所搜关键词(不可含引用问题,见 core 转义) */
static int g_tab; /* 0=单曲 1=歌单 */
static int g_searched; /* 1=已提交过搜索(区分「输入后未搜」空态文案)*/
static int g_req_tab, g_req_offset, g_req_replace;
static volatile int g_more_err; /* 翻页失败(snack 一次)*/
static void *search_worker(void *arg); /* 前向声明(sr_maybe_load_more 先引用) */
static void sr_drag_reset(void)
{
g_press_row = -1; g_press_delta = 0; g_dragging = 0; g_drag_last_y = 0;
}
/* 当前视图(§23 历史/结果/空态)。由 g_st.search_query 是否为空 + 各页签结果数推导。 */
static int sr_view(void)
{
if (g_st.search_query[0] == 0)
return (appstate_search_history_count() > 0) ? SR_HIST : SR_EMPTY;
if (appstate_search_count(g_tab) > 0) return SR_RES;
return SR_EMPTY;
}
static int sr_count(void)
{
int v = sr_view();
if (v == SR_HIST) return appstate_search_history_count();
if (v == SR_RES) return appstate_search_count(g_tab);
return 0;
}
static void sr_save_scroll(void)
{
if (g_tab == 0) g_scroll_song = meow_listview_scroll(g_list);
else g_scroll_pl = meow_listview_scroll(g_list);
}
static void sr_restore_scroll(void)
{
meow_listview_set_scroll(g_list, (g_tab == 0) ? g_scroll_song : g_scroll_pl);
}
static int sr_src2(int idx, meow_list_item *out, void *ctx)
{
(void)ctx;
int v = sr_view();
if (v == SR_HIST) {
char q[NCM_SEARCH_HIST_LEN];
if (!appstate_search_history_get(idx, q, sizeof q)) return 0;
out->icon_kind = MEOW_LIST_ICON_NONE;
out->title = q;
out->subtitle = "";
out->right = MEOW_LIST_RIGHT_NONE;
out->on = 0; out->enabled = 1;
return 1;
}
if (v == SR_RES) {
if (g_tab == 0) {
static ncm_song_t s;
if (appstate_search_song(idx, &s) != 0) return 0;
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 snprintf(sub, sizeof sub, "%s", s.album_name);
out->icon_kind = MEOW_LIST_ICON_NONE;
out->title = s.name;
out->subtitle = sub;
} else {
static ncm_playlist_t p;
if (appstate_search_pl(idx, &p) != 0) return 0;
static char sub[64];
snprintf(sub, sizeof sub, "%d 首", p.track_count);
out->icon_kind = MEOW_LIST_ICON_NONE;
out->title = p.name;
out->subtitle = sub;
}
out->right = MEOW_LIST_RIGHT_ARROW;
out->on = 0; out->enabled = 1;
return 1;
}
return 0; /* SR_EMPTY:无行 */
}
static void sr_draw_empty(void *ctx)
{
(void)ctx;
if (meow_ui_activity_active() != ACT_SEARCH) return;
if (sr_view() != SR_EMPTY) return; /* 历史/结果态有行,空态不画 */
if (g_loading) { ncm_draw_empty(r_list, "搜索中", "正在搜索..."); return; }
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_query[0]) ncm_draw_empty(r_list, "输入关键词", "输入后点「搜索」");
else if (!g_searched) ncm_draw_empty(r_list, "输入后点「搜索」", "或点历史记录");
else ncm_draw_empty(r_list, "没有结果",
g_tab == 0 ? "未找到相关歌曲" : "未找到相关歌单");
}
static void sr_draw_footer(void *ctx)
{
(void)ctx;
if (meow_ui_activity_active() != ACT_SEARCH) return;
int v = sr_view();
if (v == SR_HIST) { /* 历史:右缘「清空全部」按钮 */
const meow_theme *th = meow_theme_get();
const ncm_pal_t *pa = ncm_palette(g_dark);
int cw = meow_ui_text_width("清空全部", th->font_body);
int fx = r_cont.x + r_cont.w - 16 - cw;
int fy = r_cont.y + r_cont.h - APP_FOOTER_H + (APP_FOOTER_H - th->font_body) / 2;
meow_ui_text(fx, fy, "清空全部", th->font_body, pa->red);
return;
}
if (v == SR_RES) {
int n = appstate_search_count(g_tab);
if (n > 0) {
char foot[96];
snprintf(foot, sizeof foot, "%s %d %s%s",
g_tab == 0 ? "单曲" : "歌单", n,
g_tab == 0 ? "个结果" : "个歌单",
appstate_search_has_more(g_tab) ? " / 加载更多" : "");
ncm_draw_footer(r_cont, foot);
}
}
}
static void sr_draw_tabs(void *ctx)
{
(void)ctx;
if (meow_ui_activity_active() != ACT_SEARCH) return;
if (sr_view() != SR_RES) return; /* 页签只在结果态显示 */
const meow_theme *th = meow_theme_get();
const ncm_pal_t *pa = ncm_palette(g_dark);
static const char *lab[2] = { "单曲", "歌单" };
for (int i = 0; i < 2; i++) {
int on = (g_tab == i);
uint32_t col = on ? pa->red : th->onSurfaceVariant;
meow_ui_text_center(r_tabs[i].x + r_tabs[i].w / 2, r_tabs[i].y + (r_tabs[i].h - th->font_body) / 2,
lab[i], th->font_body, col);
if (on) meow_ui_fill_rect(r_tabs[i].x, r_tabs[i].y + r_tabs[i].h - 3, r_tabs[i].w, 3, pa->red);
}
}
static void sr_draw_btn(void *ctx)
{
(void)ctx;
if (meow_ui_activity_active() != ACT_SEARCH) return;
const ncm_pal_t *pa = ncm_palette(g_dark);
ncm_draw_button(r_btn.x, r_btn.y, r_btn.w, r_btn.h, "搜索", pa->red, pa->on_red);
}
static void sr_apply(void)
{
if (g_list) meow_listview_set_count(g_list, sr_count());
const meow_theme *th = meow_theme_get();
meow_ui_set_page_bg(th->bg);
meow_ui_paint_full();
}
/* 触底翻页(§23):RES 态 + 还有下一页 + 未在载 → 按当前页签的 offset 拉下一页。
* 仅由用户滚动动作触发(风控:翻页=用户动作)。 */
static void sr_maybe_load_more(void)
{
if (sr_view() != SR_RES) return;
if (g_thr_on || g_loading || g_st.search_err != 0) return;
int n = appstate_search_count(g_tab);
int cap = (g_tab == 0) ? NCM_SEARCH_SONG_MAX : NCM_SEARCH_PL_MAX;
if (n <= 0 || n >= cap || !appstate_search_has_more(g_tab)) return;
int item = g_item_h;
int scroll = meow_listview_scroll(g_list);
if (scroll + r_list.h < n * item - item * 2) return; /* 未近底 */
g_req_tab = g_tab; g_req_offset = n; g_req_replace = 0;
/* 单飞:无 worker 才发(search_worker 尾部解锁) */
g_thr_on = 1; g_loading = 1; g_more_err = 0;
if (ncm_thread_create(&g_thr, search_worker, NULL) != 0) {
g_thr_on = 0; g_loading = 0; g_more_err = 1;
}
}
static void *search_worker(void *arg)
{
(void)arg;
int tab = g_req_tab, off = g_req_offset, repl = g_req_replace;
const char *kw = g_query;
int rc = NCM_ERR_IO, n = 0;
int64_t total = -1;
if (tab == 0) {
static ncm_song_t sbuf[NCM_SEARCH_PAGE];
rc = ncm_api_cloudsearch_song(g_st.ctx.device_id, g_st.ctx.cookie, kw,
off, NCM_SEARCH_PAGE, sbuf, NCM_SEARCH_PAGE, &n, &total);
pthread_mutex_lock(&g_mu);
if (rc == NCM_OK) {
if (repl) appstate_search_clear(0);
appstate_search_append_songs(n, sbuf, total);
g_st.search_err = 0; g_more_err = 0;
} else if (repl) g_st.search_err = rc;
else g_more_err = 1;
} else {
static ncm_playlist_t pbuf[NCM_SEARCH_PAGE];
rc = ncm_api_cloudsearch_playlist(g_st.ctx.device_id, g_st.ctx.cookie, kw,
off, NCM_SEARCH_PAGE, pbuf, NCM_SEARCH_PAGE, &n, &total);
pthread_mutex_lock(&g_mu);
if (rc == NCM_OK) {
if (repl) appstate_search_clear(1);
appstate_search_append_pls(n, pbuf, total);
g_st.search_err = 0; g_more_err = 0;
} else if (repl) g_st.search_err = rc;
else g_more_err = 1;
}
g_loading = 0;
g_gen++;
pthread_mutex_unlock(&g_mu);
return NULL;
}
void search_submit(const char *kw)
{
if (!kw || !kw[0]) { ncm_snack("请输入关键词"); return; }
ncm_strlcpy(g_query, kw, sizeof g_query);
ncm_strlcpy(g_st.search_query, kw, sizeof g_st.search_query);
appstate_search_history_add(kw); /* §23:历史(去重+最新在前+≤12)*/
g_searched = 1;
g_scroll_song = g_scroll_pl = 0;
if (g_list) { meow_listview_set_scroll(g_list, 0); }
appstate_search_clear(g_tab ^ 1); /* 新查询:清非当前页签,切过去时懒加载新词 */
if (g_host_mock) { /* 宿主/测试:预置结果,同步 */
g_loading = 0; g_st.search_err = 0; sr_apply(); return;
}
if (g_thr_on) return; /* 单飞:已有 worker 在跑 */
g_req_tab = g_tab; g_req_offset = 0; g_req_replace = 1;
g_st.search_err = 0;
g_loading = 1; g_more_err = 0;
g_thr_on = 1;
if (ncm_thread_create(&g_thr, search_worker, NULL) != 0) {
g_thr_on = 0; g_loading = 0; g_st.search_err = NCM_ERR_IO;
}
sr_apply();
}
/* 切页签:保存旧滚动 → 换页签 → 恢复该页签滚动;空结果页签懒加载(用户切页签动作)。 */
static void sr_set_tab(int t)
{
if (t == g_tab) return;
sr_save_scroll();
g_tab = t;
g_st.search_tab = t; /* 应用态同步(重启/重进保持) */
sr_restore_scroll();
sr_apply();
if (g_st.search_query[0] && !g_thr_on && !g_loading &&
g_st.search_err == 0 && appstate_search_count(g_tab) == 0) {
g_req_tab = g_tab; g_req_offset = 0; g_req_replace = 1;
g_loading = 1; g_more_err = 0;
g_thr_on = 1;
if (ncm_thread_create(&g_thr, search_worker, NULL) != 0) {
g_thr_on = 0; g_loading = 0;
}
}
}
void search_tick(uint64_t now)
{
(void)now;
chrome_tick();
if (!g_thr_on) return;
if (g_gen == g_acked) return;
g_acked = g_gen;
g_thr_on = 0;
g_loading = 0;
if (g_more_err) { ncm_snack("加载失败"); g_more_err = 0; }
sr_apply();
}
void search_open(void)
{
meow_view_page_push(ACT_SEARCH);
}
int search_is_active(void) { return g_sc.active; }
int search_on_tap(int x, int y)
{
if (g_tb) {
int ah = meow_topappbar_hit(g_tb, x, y);
if (ah == MEOW_TOPBAR_BACK) { sr_drag_reset(); meow_view_page_pop(); return 1; }
if (ah >= 0) { sr_drag_reset(); return 1; }
}
if (x >= r_btn.x && x < r_btn.x + r_btn.w && y >= r_btn.y && y < r_btn.y + r_btn.h) {
const char *t = meow_textfield_text(g_field); /* 「搜索」确认(风控:仅此处发) */
search_submit(t ? t : "");
return 1;
}
int v = sr_view();
if (v == SR_RES) { /* 页签切换 */
for (int i = 0; i < 2; i++)
if (x >= r_tabs[i].x && x < r_tabs[i].x + r_tabs[i].w &&
y >= r_tabs[i].y && y < r_tabs[i].y + r_tabs[i].h) { sr_set_tab(i); return 1; }
}
if (v == SR_HIST && /* 历史「清空全部」按钮 */
y >= r_cont.y + r_cont.h - APP_FOOTER_H && y < r_cont.y + r_cont.h &&
x >= r_cont.x + r_cont.w - 16 - 70) {
sr_drag_reset();
appstate_search_history_clear();
sr_apply();
return 1;
}
if (g_field && meow_widget_hit(g_field, x, y)) { /* 唤 IME */
meow_textfield_activate(g_field);
return 1;
}
if (meow_widget_hit(g_list, x, y)) {
if (v == SR_EMPTY) { /* 失败态:点内容区重试(风控:用户动作) */
if (g_st.search_err && g_st.search_query[0]) {
sr_drag_reset(); g_st.search_err = 0;
if (!g_thr_on) {
g_req_tab = g_tab; g_req_offset = 0; g_req_replace = 1;
g_loading = 1;
g_thr_on = 1;
if (ncm_thread_create(&g_thr, search_worker, NULL) != 0) {
g_thr_on = 0; g_loading = 0; g_st.search_err = NCM_ERR_IO;
}
}
return 1;
}
sr_drag_reset();
return 1;
}
/* 误触修复(§13.3/§23):按下行 + 拖动>10 抑制(对齐 home/playlist) */
int was_drag = (g_press_delta > 10);
int row = (g_press_row >= 0) ? g_press_row : meow_listview_hit(g_list, x, y);
sr_drag_reset();
if (row < 0 || was_drag) return 1;
if (v == SR_HIST) {
char q[NCM_SEARCH_HIST_LEN];
if (appstate_search_history_get(row, q, sizeof q)) search_submit(q);
return 1;
}
if (g_tab == 0) player_play_search_song(row); /* 单曲:搜索队列起播(§23)*/
else {
ncm_playlist_t p;
if (appstate_search_pl(row, &p) == 0) playlist_open_pl(&p); /* 歌单:进详情 */
}
return 1;
}
return 0;
}
int search_swipe_left(void)
{
if (sr_view() != SR_HIST) return 0; /* 仅历史模式左滑删单条 */
int row = g_press_row; /* touch_down 已记按下行 */
sr_drag_reset();
if (row >= 0) {
appstate_search_history_remove(row);
sr_apply();
return 1; /* 已消费:不触返回 */
}
return 0;
}
void search_touch_down(int x, int y)
{
sr_drag_reset();
if (meow_widget_hit(g_list, x, y)) {
int row = meow_listview_hit(g_list, x, y);
if (row >= 0) g_press_row = 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 search_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;
}
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);
sr_maybe_load_more();
}
}
void search_swipe(int dir, int dist)
{
if (dir != MEOW_SWIPE_UP && dir != MEOW_SWIPE_DOWN) return;
if (sr_view() != SR_RES) 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);
sr_maybe_load_more();
}
}
static void sr_page_create(meow_view *v, void *ctx)
{
(void)v;
((search_ctrl *)ctx)->view = v;
r_cont = ncm_content_rect();
g_item_h = ncm_row_h(); /* M12:行高按当前字体两行文本块派生(首行标题不被视口顶钳掉) */
ncm_rect_t field = NR(16, r_cont.y + 12, r_cont.w - 32, 48);
r_btn = NR(field.x, field.y + field.h + 12, field.w, 44);
int by = r_btn.y + r_btn.h + 8;
r_tabs[0] = NR(r_btn.x, by, r_btn.w / 2 - 6, 36);
r_tabs[1] = NR(r_btn.x + r_btn.w / 2 + 6, by, r_btn.w / 2 - 6, 36);
r_list = NR(16, by + 36 + 8, r_cont.w - 32,
r_cont.y + r_cont.h - APP_FOOTER_H - (by + 36 + 8));
if (r_list.h < 0) r_list.h = 0;
meow_ui_activity_push(ACT_SEARCH); /* owner=ACT_SEARCH */
g_tb = ncm_topbar_create("搜索", 1, NULL);
/* 中文搜索:IME 切 MEOW_IME_PINYIN(拼音候选上屏 UTF-8 到 g_st.search_query,经 on_change 实时回写;
* 键盘「拼/英」键可切回 ASCII 输英文,「中」热区回拼音——英文零回归)。 */
g_field = meow_textfield_create(field.x, field.y, field.w, field.h,
"输入歌曲 / 歌手", g_st.search_query,
sizeof g_st.search_query, MEOW_IME_PINYIN);
g_list = meow_listview_create(r_list.x, r_list.y, r_list.w, r_list.h, 0,
sr_src2, NULL, MEOW_LIST_SEL_NONE);
meow_listview_set_item_h(g_list, g_item_h);
meow_ui_activity_pop();
meow_widget_set_z(g_list, 10);
g_btn_id = meow_draw_custom_register(60, r_btn.x, r_btn.y, r_btn.w, r_btn.h,
sr_draw_btn, NULL);
g_tabbar_id = meow_draw_custom_register(40, r_tabs[0].x, r_tabs[0].y,
r_btn.w, r_tabs[0].h, sr_draw_tabs, NULL);
g_empty_id = meow_draw_custom_register(1, r_list.x, r_list.y, r_list.w, r_list.h,
sr_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, sr_draw_footer, NULL);
/* 页签初始 = 应用态记录值(宿主 dump 可指定 search_tab);越界回落 0。 */
g_tab = (g_st.search_tab == 0 || g_st.search_tab == 1) ? g_st.search_tab : 0;
sr_drag_reset();
}
static void sr_page_enter(meow_view *v, void *ctx)
{
(void)v;
((search_ctrl *)ctx)->active = 1;
sr_apply(); /* 进页即按当前模式设列表 count(历史/结果/空态),避免首屏空列表 */
#ifndef MEOW_UI_HOST_TEST
/* §23:进页自动弹键盘(字段为空时;返回浏览结果不打断)。宿主离屏为阻塞式模态 IME,跳过。 */
if (g_field && g_st.search_query[0] == 0) meow_textfield_activate(g_field);
#else
(void)0;
#endif
}
static void sr_page_leave(meow_view *v, void *ctx)
{
(void)v;
((search_ctrl *)ctx)->active = 0;
}
static void sr_page_destroy(meow_view *v, void *ctx)
{
(void)v; (void)ctx;
if (g_btn_id) { meow_draw_unregister(g_btn_id); g_btn_id = 0; }
if (g_tabbar_id){ meow_draw_unregister(g_tabbar_id);g_tabbar_id = 0; }
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_field){ meow_widget_free(g_field); g_field = NULL; }
if (g_tb) { meow_widget_free(g_tb); g_tb = NULL; }
}
meow_view *search_view_create(void)
{
static const meow_view_hooks h = {
.on_create = sr_page_create,
.on_enter = sr_page_enter,
.on_leave = sr_page_leave,
.on_destroy = sr_page_destroy,
};
return meow_view_create(ACT_SEARCH, MEOW_VIEW_ACTIVITY, &h, &g_sc);
}