主頁 > 作業系統 > LVGL庫入門教程 - 影片

LVGL庫入門教程 - 影片

2022-06-30 06:59:39 作業系統

影片可以說是 LVGL 中的特色之一,不過在使用影片前,請確保單片機具有足夠的性能來維持足夠的幀率,

transition:過渡影片

當一個控制元件的狀態發生改變時,可以讓樣式也發生變化以提醒用戶,通過過渡影片(transition)可以讓樣式的改變更自然,例如,按鈕在點擊時,以及開關在切換時,都具有一小段的過渡影片,

過渡影片使用 lv_style_transition_dsc_t 結構描述,為了要設定過渡影片,需要提供以下資訊:

  • 哪些屬性需要過渡
  • 過渡前的延時
  • 過渡持續的時間
  • 過渡影片(以回呼函式的形式提供)

這些資訊和結構成員是一一對應的,除了直接給結構成員賦值外,也可以使用以下初始化函式一次性設定:

void lv_style_transition_dsc_init(
                lv_style_transition_dsc_t* tr, 
                const lv_style_prop_t props[],
                lv_anim_path_cb_t path_cb, 
                uint32_t time, 
                uint32_t delay, 
                void* user_data);

第一個引數需要提供被初始化的過渡影片結構,第二個引數陣列和字串一樣需要以 0 結尾,例如,假設需要實作這樣一個過渡效果:點擊時背景顏色發生改變并拉長,那么相應的初始化程序為:

static lv_style_transition_dsc_t trans;
static const lv_style_prop_t trans_props[] = {
    LV_STYLE_WIDTH, LV_STYLE_HEIGHT, LV_STYLE_BG_COLOR, 0,
};
lv_style_transition_dsc_init(&trans, trans_props, 
            lv_anim_path_ease_in_out, 500, 0, NULL);

這里使用的過渡函式為 lv_anim_path_ease_in_out() ,這是一個內置的過渡效果,與之類似的過渡lv_anim_path_ease_out函式可以參考下表:

過渡函式 過渡效果
lv_anim_path_linear 等速過渡
lv_anim_path_ease_in 先慢后快的過渡
lv_anim_path_ease_out 先快后慢的過渡
lv_anim_path_ease_in_out 先慢、后快、結尾再變慢的過渡
lv_anim_path_overshoot 幅度會稍微過頭一些再彈回的過渡
lv_anim_path_bounce 和上一個類似,不過會比較快地多彈幾次
lv_anim_path_step 一步到位,和沒影片的區別在于多了個延時

過渡影片是控制元件樣式的一部分,可以將初始化得到的過渡影片描述應用到樣式上:

static lv_style_t style_trans;
lv_style_init(&style_trans);
lv_style_set_transition(&style_trans, &trans);

過渡影片只有在兩種樣式切換時才會發生,例如,如果讓以上樣式應用在按下狀態下:

lv_style_set_bg_color(&style_trans, lv_palette_main(LV_PALETTE_RED));
lv_style_set_width(&style_trans, 150);
lv_style_set_height(&style_trans, 60);
lv_obj_add_style(obj, &style_trans, LV_STATE_PRESSED);

那么只有在從其它狀態變為按下時才會發生過渡:

注意松開時樣式是突然轉變的,如果要給這部分也添加一個過渡效果,可以給默認狀態下的控制元件添加一個包含過渡的樣式,

animate:通用影片

過渡只有在狀態改變時才會發生,而影片可以在任意時刻進行,除此之外,兩者的區別還有:過渡只是樣式的一部分,而影片和樣式之間是獨立的,

實際上,過渡的底層也使用的是影片,

創建影片

為了創建影片,需要像樣式一樣宣告一個影片型別并初始化:

lv_anim_t anim;
lv_anim_init(&anim);

由于影片是立即執行的,因此可以使用自動變數存盤,然后,需要明確該影片將作用于哪一個控制元件:

lv_anim_set_var(&anim, obj);

接下來,可以設定影片的各種軌跡,包括:

  • 影片需要改變什么屬性
  • 這些屬性改變的范圍
  • 影片效果
  • 延時和持續時間

影片的這些屬性和過渡是類似的,例如,假設想做一個控制元件下落的影片,那么需要提供一個改變 y 坐標值的回呼函式,這個函式可以直接使用 lv_obj_set_y() ,然后設定改變的始末值和運動軌跡,對應的代碼為:

lv_anim_set_exec_cb(&anim, (lv_anim_exec_xcb_t)lv_obj_set_y);
lv_anim_set_values(&anim, -100, 100);
lv_anim_set_path_cb(&anim, lv_anim_path_bounce);
lv_anim_set_time(&anim, 1000);
lv_anim_set_delay(&anim, 1000);

然后,可以在必要的時候執行影片:

lv_anim_start(&anim);

效果為:

關于延遲渲染
之前說過,樣式是延遲渲染的,因此樣式變數需要使用 static 存盤型別修飾符;而影片不是,影片從創建到執行是立即發生的,這也很好理解:樣式在創建的程序中可能發生多次修改,因此需要確定最終的表現結果如何,再著手繪制,否則整個控制元件可能會重繪多次,占用大量無效的資源,
這種特點可能會帶來許多意想不到的問題,例如,假設在 lv_anim_set_values() 函式中去獲取一個控制元件的位置、寬度等資訊,由于它們都屬于樣式的一部分,此時還沒有實際計算,因此得到的可能是默認值,造成影片始末效果偏離預期軌跡,
要解決這個問題,要么手動設定具體的值,要么讓影片等到實際渲染發生了再執行,例如將其作為事件回呼函式中的一部分,

更復雜的影片

以上創建的影片是單次不重復的,LVGL 提供了許多函式,可以為影片設定更復雜的屬性,

這里介紹一個控制元件 bar ,它實質上就是沒有 knob 部分的滑塊,可以借用該控制元件來創建一個進度條(progress bar)影片,以下創建一個 bar 并將它的模式設定為 LV_BAR_MODE_RANGE ,這樣就可以同時修改 indicator 兩端的位置了:

lv_obj_t* bar = lv_bar_create(lv_scr_act());
lv_bar_set_mode(bar, LV_BAR_MODE_RANGE);

這里使用官方檔案中提供的一個樣式來使外觀更好看,具體細節就無需解釋了:

static lv_style_t style_bg;
static lv_style_t style_indic;
lv_style_init(&style_bg);
lv_style_set_border_color(&style_bg, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_border_width(&style_bg, 2);
lv_style_set_pad_all(&style_bg, 6);
lv_style_set_radius(&style_bg, 6);
lv_style_set_anim_time(&style_bg, 1000);
lv_style_init(&style_indic);
lv_style_set_bg_opa(&style_indic, LV_OPA_COVER);
lv_style_set_bg_color(&style_indic, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_radius(&style_indic, 3);
lv_obj_remove_style_all(bar);
lv_obj_add_style(bar, &style_bg, 0);
lv_obj_add_style(bar, &style_indic, LV_PART_INDICATOR);
lv_obj_set_size(bar, 200, 20);

然后就可以確定影片效果了,例如,這里期望的影片效果為:

那么首先可以撰寫一個改變屬性的回呼函式,例如改變 indicator 的范圍:

static void anim_progress_load(void* obj, int32_t v) {
    lv_bar_set_start_value(obj, v, LV_ANIM_ON);
    lv_bar_set_value(obj, 20 + v, LV_ANIM_ON);
}

這些值在 0~80 范圍內等速改變,持續時間 1.5 秒,無延時,對應的代碼為:

lv_anim_set_exec_cb(&anim, anim_progress_load);
lv_anim_set_values(&anim, 0, 80);
lv_anim_set_path_cb(&anim, lv_anim_path_linear);
lv_anim_set_time(&anim, 1500);
lv_anim_set_delay(&anim, 0);

然后這里為其添加一個倒退和重復效果,這樣影片就能來回播放了:

lv_anim_set_playback_time(&anim, 1500);
lv_anim_set_repeat_count(&anim, LV_ANIM_REPEAT_INFINITE);

實作的進度條影片就像以上 gif 展示的一樣,除此之外,還可以修改更多影片的細節,例如:

函式 設定內容
lv_anim_set_start_cb(anim, start_cb) 在延時后、開始前執行一個函式
lv_anim_set_playback_delay(anim, delay) 設定影片倒退前的延時
lv_anim_set_repeat_delay(anim, delay) 設定影片重復前的延時
lv_anim_set_early_apply(&a, bool) 是否將起始值應用到影片開始前,使影片執行時不會太突兀

更多的細節可以參考官方檔案,

組合影片效果

有時候需要同時播放較多影片,此時如果逐個播放的話,需要逐個為影片設計延時,不方便安排,此時,可以使用 LVGL 提供的時間線(timeline)統一安排各個影片,

時間線的創建非常簡單,首先,創建一系列影片,但先不呼叫 lv_anim_start() 讓影片開始,

其次,創建一個時間線并將各個影片添加到時間線的某一時刻處:

lv_anim_timeline_t* anim_timeline = lv_anim_timeline_create();
lv_anim_timeline_add(anim_timeline, 0, &anim_axis);
lv_anim_timeline_add(anim_timeline, 100, &anim_obj_01);
lv_anim_timeline_add(anim_timeline, 1100, &anim_obj_02);
lv_anim_timeline_add(anim_timeline, 2100, &anim_obj_03);
lv_anim_timeline_add(anim_timeline, 300, &anim_label_01);
lv_anim_timeline_add(anim_timeline, 1300, &anim_label_02);
lv_anim_timeline_add(anim_timeline, 2300, &anim_label_03);

使用時間線時,無需為影片設計延時,只需要關注影片會在什么時刻播放,延時便會自動計算,

添加完畢后,再呼叫時間線的執行函式就可以了:

lv_anim_timeline_start(anim_timeline);

這樣就可以創建很復雜的組合影片效果了:

使用時間線可以方便管理所有影片,可以將時間線上包含的所有影片停播、倒放、跳轉等,以下列出了一些常用的時間線控制函式:

函式 用途
lv_anim_timeline_stop(timeline) 暫停播放當前的所有影片
lv_anim_timeline_set_reverse(timeline, bool) 設定接下來的播放方向
lv_anim_timeline_set_progress(timeline, progress) 跳轉到播放進度

如果需要倒放,在設定了播放方向后還需要呼叫 lv_anim_timeline_start() 重新播放,并且會從當前位置倒放,

scroll:滾動影片

滾動的特點

滾動也是常見的一種影片效果,如果一個容器的尺寸不足以容納它包含的控制元件,那么它就可以通過滾動來展示包含控制元件的所有部分,

為了使一個控制元件是可滾動的,它需要擁有標志 LV_OBJ_FLAG_SCROLLABLE ,清除該標志可以隱藏子控制元件的溢位部分,

滾動是可以冒泡的,如果一個控制元件已經滾動到底,再次對其嘗試滾動將使滾動事件傳播到父容器上,可以通過清除 LV_OBJ_FLAG_SCROLL_CHAIN 標志位去除這個性質,

可以通過 lv_obj_set_scroll_dir() 限制滾動的方向,例如:

lv_obj_set_scroll_dir(obj, LV_DIR_RIGHT);

那么就只能向右滾動到底,不能向左折回,

還可以通過以下幾個函式利用代碼執行滾動:

lv_obj_scroll_to(obj, x, y, anim_en);
lv_obj_scroll_by(obj, x, y, anim_en);
lv_obj_scroll_to_view(child, anim_en);

注意前兩個函式的區別:前者是滾動到相應的位置,多次呼叫只有第一次實際有效;后者是模擬滾動的操作,實際滾動方向是相反的,并且多次呼叫效果可以疊加,除此之外,后者甚至可以滾動到超出子控制元件的范圍之外,最后一個函式自動滾動到合適的位置,確保子控制元件可視,

這幾個函式都不受滾動方向的約束,它們都具有第三個引數,用于指定滾動時是否提供滾動影片,

滾動影片

滾動是有影片的,默認情況下,滾動影片的特點表現在以下幾點:

  • 滾動是具有慣性的,意思是當輸入設備停止互動時,控制元件還會繼續向前滾動一小段距離,可以通過清除 LV_OBJ_FLAG_SCROLL_MOMENTUM 標志位取消這個特征
  • 滾動是具有彈性的,當滾動到底時,繼續嘗試滾動會使控制元件超出一定范圍,松開后回彈,可以通過清除 LV_OBJ_FLAG_SCROLL_ELASTIC 標志位取消這個特征
  • 除此之外,以上介紹的兩個代碼實作滾動的函式,如果在第三個引數中應用滾動,那么會發生一小段 easy-out 的切換影片

還可以設定一種特殊的滾動效果 snap ,它使滾動時可以自動對齊,為了啟用這種效果,需要添加 LV_OBJ_FLAG_SNAPPABLE 標志位,然后設定對齊的方式:

lv_obj_set_scroll_snap_x(cont, LV_SCROLL_SNAP_START);

這樣便可以按開始位置對齊了:

還可以配合 LV_OBJ_FLAG_SCROLL_ONE 標志位一次只滾過最多一個控制元件的位置,


在滾動時,會觸發 LV_EVENT_SCROLL 事件,可以通過在該事件回呼函式中對包含的子控制元件做變換,實作更復雜的滾動效果,

例如,以下在事件回呼函式內,根據每個子控制元件當前位置的縱坐標對橫坐標做一些變換:

static scrool_widget_cb(lv_event_t* e) {
    lv_obj_t* cont = lv_event_get_target(e);
    uint32_t child_cnt = lv_obj_get_child_cnt(cont);
    for (uint8_t i = 0; i < child_cnt; i++) {
        lv_obj_t* child = lv_obj_get_child(cont, i);
        lv_obj_set_style_translate_x(child, child->coords.y1 * 0.5 - 60, 0);
    }
}

然后讓每次滾動時都做以上變換:

lv_obj_add_event_cb(cont, scrool_widget_cb, LV_EVENT_SCROLL, NULL);

這樣就能實作斜方向的滾動效果了:

這里由于僅在事件中才修改按鈕的水平位置,因此一開始控制元件的擺放不是傾斜的,要解決這個問題,可以添加以下代碼:

lv_obj_scroll_to_view(lv_obj_get_child(cont, 0), LV_ANIM_OFF);
lv_event_send(cont, LV_EVENT_SCROLL, NULL);

前者使各個控制元件的坐標被計算,后者手動觸發事件回呼函式,利用計算出的坐標執行位置變換,

LVGL 的官方檔案還給出了一個示例,可以實作類似圓形的旋轉滾動,效果非常不錯,不過涉及的計算較多,感興趣的可以自行閱讀官方檔案,

滾動條

如果一個控制元件可以發生滾動,那么它就具有滾動條(scrollbar),可以通過 lv_obj_set_scrollbar_mode() 函式修改滾動條的模式,例如,使用 LV_SCROLLBAR_MODE_OFF 模式可以使滾動條完全消失,就像上一張 gif 顯示的那樣,

滾動條是一個控制元件的 LV_PART_SCROLLBAR 部分,可以通過選擇器給滾動條加上不同的樣式,

首發于:http://frozencandles.fun/archives/425

參考資料/延伸閱讀

https://docs.lvgl.io/master/overview/animation.html

https://docs.lvgl.io/master/overview/scroll.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/497675.html

標籤:其他

上一篇:Linux 磁盤型別和結構

下一篇:MariaDB的安裝與配置

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • CA和證書

    1、在 CentOS7 中使用 gpg 創建 RSA 非對稱密鑰對 gpg --gen-key #Centos上生成公鑰/密鑰對(存放在家目錄.gnupg/) 2、將 CentOS7 匯出的公鑰,拷貝到 CentOS8 中,在 CentOS8 中使用 CentOS7 的公鑰加密一個檔案 gpg -a ......

    uj5u.com 2020-09-10 00:09:53 more
  • Kubernetes K8S之資源控制器Job和CronJob詳解

    Kubernetes的資源控制器Job和CronJob詳解與示例 ......

    uj5u.com 2020-09-10 00:10:45 more
  • VMware下安裝CentOS

    VMware下安裝CentOS 一、軟硬體準備 1 Centos鏡像準備 1.1 CentOS鏡像下載地址 下載地址 1.2 CentOS鏡像下載程序 點擊下載地址進入如下圖的網站,選擇需要下載的版本,這里選擇的是Centos8,點擊如圖所示。 決定選擇Centos8后,選擇想要的鏡像源進行下載,此 ......

    uj5u.com 2020-09-10 00:12:10 more
  • 如何使用Grep命令查找多個字串

    如何使用Grep 命令查找多個字串 大家好,我是良許! 今天向大家介紹一個非常有用的技巧,那就是使用 grep 命令查找多個字串。 簡單介紹一下,grep 命令可以理解為是一個功能強大的命令列工具,可以用它在一個或多個輸入檔案中搜索與正則運算式相匹配的文本,然后再將每個匹配的文本用標準輸出的格式 ......

    uj5u.com 2020-09-10 00:12:28 more
  • git配置http代理

    git配置http代理 經常遇到克隆 github 慢的問題,這里記錄一下幾種配置 git 代理的方法,解決 clone github 過慢。 目錄 git配置代理 git單獨配置github代理 git配置全域代理 配置終端環境變數 git配置代理 主要使用 git config 命令 git單獨 ......

    uj5u.com 2020-09-10 00:12:33 more
  • Linux npm install 裝包時提示Error EACCES permission denied解

    npm install 裝包時提示Error EACCES permission denied解決辦法 ......

    uj5u.com 2020-09-10 00:12:53 more
  • Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包

    Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包。 18 (flaskApi) [root@67 flaskDemo]# yum -y install nginx 19 已加載插件:fastestmirror, langpacks 20 Loading ......

    uj5u.com 2020-09-10 00:13:13 more
  • Linux查看服務器暴力破解ssh IP

    在公網的服務器上經常遇到別人爆破你服務器的22埠,用來挖礦或者干其他嘿嘿嘿的事情~ 這種情況下正確的做法是: 修改默認ssh的22埠 使用設定密鑰登錄或者白名單ip登錄 建議服務器密碼為復雜密碼 創建普通用戶登錄服務器(root權限過大) 建立堡壘機,實作統一管理服務器 統計爆破IP [root ......

    uj5u.com 2020-09-10 00:13:17 more
  • CentOS 7系統常見快捷鍵操作方式

    Linux系統中一些常見的快捷方式,可有效提高操作效率,在某些時刻也能避免操作失誤帶來的問題。 ......

    uj5u.com 2020-09-10 00:13:31 more
  • CentOS 7作業系統目錄結構介紹

    作業系統存在著大量的資料檔案資訊,相應檔案資訊會存在于系統相應目錄中,為了更好的管理資料資訊,會將系統進行一些目錄規劃,不同目錄存放不同的資源。 ......

    uj5u.com 2020-09-10 00:13:35 more
最新发布
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:43:21 more
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:42:36 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:26:53 more
  • 設定Windows主機的瀏覽器為wls2的默認瀏覽器

    這里以Chrome為例。 1. 準備作業 wsl是可以使用Windows主機上安裝的exe程式,出于安全考慮,默認情況下改功能是無法使用。要使用的話,終端需要以管理員權限啟動。 我這里以Windows Terminal為例,介紹如何默認使用管理員權限打開終端,具體操作如下圖所示: 2. 操作 wsl ......

    uj5u.com 2023-04-19 09:25:49 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:19:04 more
  • Linux學習筆記

    IP地址和主機名 IP地址 ifconfig可以用來查詢本機的IP地址,如果不能使用,可以通過install net-tools安裝。 Centos系統下ens33表示主網卡;inet后表示IP地址;lo表示本地回環網卡; 127.0.0.1表示代指本機;0.0.0.0可以用于代指本機,同時在放行設 ......

    uj5u.com 2023-04-18 06:52:01 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:50 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:01 more
  • 你是不是暴露了?

    作者:袁首京 原創文章,轉載時請保留此宣告,并給出原文連接。 如果您是計算機相關從業人員,那么應該經歷不止一次網路安全專項檢查了,你肯定是收到過資訊系統技術檢測報告,要求你加強風險監測,確保你提供的系統服務堅實可靠了。 沒檢測到問題還好,檢測到問題的話,有些處理起來還是挺麻煩的,尤其是線上正在運行的 ......

    uj5u.com 2023-04-05 16:52:56 more
  • 細節拉滿,80 張圖帶你一步一步推演 slab 記憶體池的設計與實作

    1. 前文回顧 在之前的幾篇記憶體管理系列文章中,筆者帶大家從宏觀角度完整地梳理了一遍 Linux 記憶體分配的整個鏈路,本文的主題依然是記憶體分配,這一次我們會從微觀的角度來探秘一下 Linux 內核中用于零散小記憶體塊分配的記憶體池 —— slab 分配器。 在本小節中,筆者還是按照以往的風格先帶大家簡單 ......

    uj5u.com 2023-04-05 16:44:11 more