Files
MeowOS-For-R3P2/patch_v2/ncm_app/app/ui/search.c
T
AskaEth 68ce46a5d8 fix(ncm §32): 内存瘦身修 OOM 被杀 —— 封面降采样(8.28MB→0.78MB) + 瞬态 rbuf 缩减 + 线程栈显式
真机 dmesg 实锤:OOM Kill ncm (score 460, anon-rss 26.9MB, 设备 56MB)。
画像:封面全分辨率 RGBA 8.28MB(1448x1448 原生解码驻留) 是最大可控块。

瘦身(按收益排序):
1. sdk meow_ui_img 新增纯增量 meow_img_downscale + cover.c cover_cap(≤480px)
   → 封面 8.28MB→0.78MB,-7.65MB(mem_sim 实测 PASS)。
2. ncm_api.c 瞬态响应 rbuf:song_url→64KB、lyric/song_detail/cloudsearch/user_playlist→256KB
   (detail/track_all 保 1MB)。
3. ncm_app_internal.h 新增 ncm_thread_create(显式 128KB 栈),替换全部 14 处 pthread_create。
4. 滑动窗口/meta 复核零回退(window_sim:608B/首,6000 首 280KB 恒定)。

验证:mem_sim 封面收益 PASS + host home/player 渲染 OK + stream_sim/player_flow_sim/
window_sim/search_sim/cache_evict_sim 全 PASS + test_ncm_core host+mipsel(qemu) PASS
+ build_ncm.sh -Wall -Wextra 0 warning。真机 scp 播放在跑确认(缓存曲,0 播放请求)。

新 ncm md5 44fa16fe(text 1015150/bss 1362500)。正式部署留主会话。
2026-09-02 03:43:42 +08:00

521 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 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 (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 = APP_ROW_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();
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, APP_ROW_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);
}