【AI全家桶】UI
authorCaisking <Casiking@zhihuishixun.com>
Mon, 28 Apr 2025 03:01:57 +0000 (11:01 +0800)
committerCaisking <Casiking@zhihuishixun.com>
Mon, 28 Apr 2025 03:01:57 +0000 (11:01 +0800)
33 files changed:
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceBluetoothFailedStartView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceConnectingView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceModel.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoicePresenter.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceChatContentListAdapter.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceChatContentListItemView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceConnectTimeoutView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceListeningView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceMobileDataFailedStartView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceReturnResultTextView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceThinkingView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/ChatContentItem.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/ApiKeysDeleteView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/ApiKeysPresenter.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/NotSetApiKeysView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/SetApiKeysView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceBluetoothFailedStartView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceConnectingView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoicePresenter.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceChatContentListAdapter.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceChatContentListItemView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceConnectTimeoutView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceListeningView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceMobileDataFailedStartView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceReturnResultTextView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceThinkingView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/ApiKeysDeleteView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/ApiKeysPresenter.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/NotSetApiKeysView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/SetApiKeysView.cpp [new file with mode: 0644]

diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceBluetoothFailedStartView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceBluetoothFailedStartView.h
new file mode 100644 (file)
index 0000000..aedba05
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-21 17:07:07
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-07-31 14:16:00
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AiVoiceBluetoothFailedStartView.h
+ */
+
+#ifndef AI_VOICE_BLUETOOTH_FAILEDSTART_VIEW_H
+#define AI_VOICE_BLUETOOTH_FAILEDSTART_VIEW_H
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_button.h"
+#include "components/ui_image_view.h"
+
+namespace OHOS
+{
+    static constexpr const char *ALERT_APPBLUETOOTH_AND_4GNETWORK_ENSURE_BUTTON_VIEW_ID = "AppBluetoothAnd4gNetworkEnsureButton";//APP蓝牙与4G网络都连接异常界面的确定按钮
+
+    class AiVoiceBluetoothFailedStartView
+    {
+    public:
+        struct LabelConfig
+        {
+            int16_t left;
+            int16_t top;
+            int16_t width;
+            int16_t height;
+            int16_t fontSize;
+            int16_t lineHeigh;
+            uint16_t textId;
+            uint8_t lineBreakMode;
+        };
+        struct ButtonConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+            const char *ViewId;
+        };
+
+        struct ImageConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+        };
+        
+        AiVoiceBluetoothFailedStartView();
+        ~AiVoiceBluetoothFailedStartView();
+        static AiVoiceBluetoothFailedStartView *GetInstance(void);
+        UIScrollView *CreateAiVoiceBluetoothFailedStartView(void);
+        void UpdateTitleTextId(int textId);
+
+    private:
+        void ClearAll(void);
+        UILabelExt *AiVoiceBluetoothFailedStartLabelInit(LabelConfig &labelconfig);
+        UIButton *AiVoiceBluetoothFailedStartButtonInit(ButtonConfig &buttonconfig);
+        UIImageView *AiVoiceBluetoothFailedStartImageInit(ImageConfig &imageconfig);
+        bool CreateAiVoiceBluetoothFailedStartLabel(void);
+        bool CreateAiVoiceBluetoothFailedStartButton(void);
+        bool CreateAiVoiceBluetoothFailedStartImage(void);
+        bool CreateAiVoiceBluetoothFailedStartScrollView(void);
+        UIScrollView *scrollView{nullptr};
+        UILabelExt *title{nullptr};
+        UIImageView *attentionImage{nullptr};
+        UILabelExt *label[2]{nullptr};
+        UILabelExt *ensure{nullptr};
+        UIButton *ensureButton{nullptr};
+    };
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceConnectingView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceConnectingView.h
new file mode 100644 (file)
index 0000000..4f69a4e
--- /dev/null
@@ -0,0 +1,87 @@
+/***
+ * @Date: 2024-08-19 19:20:08
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-08-30 18:57:30
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AiVoiceConnectingView.h
+ */
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-08-03 11:09:56
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-08-31 15:11:11
+ * @FilePath: /xts_origin/FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AiVoiceConnectingView.h
+ */
+
+#ifndef AIVOICE_CONNECTING_H
+#define AIVOICE_CONNECTING_H
+#include "components/ui_button.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_image_animator.h"
+namespace OHOS
+{
+    static constexpr const char *AIVOICECONNECTINGVIEW_CANCEL_BUTTON_VIEW_ID = "AivoiceConnectingcancelButton"; // 正在连接中界面取消按钮
+    static constexpr int16_t AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES = 60;                            // 图片帧数
+
+    class AiVoiceConnectingView
+    {
+    public:
+        struct LabelConfig
+        {
+            int16_t left;
+            int16_t top;
+            int16_t width;
+            int16_t height;
+            int16_t fontSize;
+            int16_t lineHeigh;
+            uint16_t textId;
+            uint8_t lineBreakMode;
+        };
+        struct ButtonConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+            const char *viewId;
+        };
+
+        struct ImageAnimatorConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t width;
+            int16_t height;
+            ImageAnimatorInfo *imageInfoArray;
+            const ImageInfo **pathsArray;
+            uint8_t numFrames;
+            int delay;
+        };
+
+        AiVoiceConnectingView();
+        ~AiVoiceConnectingView();
+        static AiVoiceConnectingView *GetInstance(void);
+        UIScrollView *CreateAiVoiceConnectingView(void);
+        UIScrollView *CreateAiVoiceConnectingView(uint8_t);
+
+    private:
+        UIImageAnimatorView *connectingImageAnimatorInit(ImageAnimatorConfig &imageanimatorconfig);
+        UILabelExt *AiVoiceConnectingViewLabelInit(LabelConfig &labelconfig);
+        UIButton *AiVoiceConnectingViewButtonInit(ButtonConfig &buttonconfig);
+        bool CreateAiVoiceConnectingViewLabel(void);
+        bool CreateAiVoiceConnectingViewButton(void);
+        bool CreateAivoiceConnectingImageAnimator(void);
+        bool CreateAiVoiceConnectingScrollView(void);
+        bool CreateAiVoiceConnectingScrollView(uint8_t);
+        void ClearAll(void);
+        UIScrollView *scrollView{nullptr};
+        UILabelExt *title{nullptr};
+        UILabelExt *cancelLabel{nullptr};
+        UIButton *cancelButton{nullptr};
+        UIImageAnimatorView *connectingAnimatorView{nullptr};
+        ImageAnimatorInfo connectingImageInfo[AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES];
+        const ImageInfo **connectingPathsArray{nullptr};
+    };
+}
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceModel.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceModel.h
new file mode 100644 (file)
index 0000000..f45155f
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-20 15:14:43
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2025-03-19 09:44:14
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AiVoiceModel.h
+ */
+#ifndef AI_VOICE_MODEL_H
+#define AI_VOICE_MODEL_H
+
+#include "iostream"
+#include "string"
+#include "iostream"
+#include "string"
+#include "ChatContentItem.h"
+#include "map"
+#define AIAUDIO_TYPE_PCM 0
+#define AIAUDIO_TYPE_SBC 1
+#define AIAUDIO_TYPE_MSBC 2
+
+// 设置当前使用的音频类型,0 表示 PCM,1 表示 SBC,2 表示 MSBC
+#define CURRENT_AIAUDIO_TYPE AIAUDIO_TYPE_SBC
+
+namespace OHOS
+{
+
+    class AiVoiceModel
+    {
+    public:
+        enum aiResponseType :uint8_t {
+                AI_RECORDING_PARSING_ERROR = 0, //AI录音解析错误
+                AI_RECORDING_PARSING_CONTENT, //AI录音解析内容
+                AI_RESPONSE_CONTENT, //AI回应内容
+                AI_RESPONSE_ERROR,//AI 回应错误
+                AI_RESPONSE_END,//AI 回应结束
+                AI_BLE_ERROR,//蓝牙数据传入错误
+        };
+
+        static AiVoiceModel &GetInstance(void); // 获取单例实例
+        bool ChangeToReturnResultTextView(void);
+        bool ChangeToAIVoiceListeningView(bool value);
+        bool ChangeToAIVoiceConnectTimeoutView();
+        void FunctionKeyOnClickToChangeAIModel(void);
+        // 初始化和状态管理
+        void StatusResume(void);
+
+        bool IsExistOpenAIAPIKeys();
+        void DeleteLocalOpenAIAPIKeys();
+        bool GetAPPBluetoothIsConnect(void);
+        bool GetMobileDataIsOpen(void);
+        bool GetAiVoiceConnectStatus(void);
+        void SetAiVoiceConnectStatus(bool state);
+        void QuerySelectedAiModelIsConnect();
+        void CancelCurAIChat(void);
+        int GetAIResponseType(void);
+        std::string GetErrnote(void);
+        void SetErrnote(std::string str);
+        void SetCurView(int16_t viewNum);
+        int GetCurView(void);
+
+        // 聊天内容管理
+        bool InitchatContentItems(void);
+        bool AddUserQuestionToChatItems();
+        bool AddAiAnswerToChatItems();
+        bool AddChatContentToItemArray(const ChatContentItem &item);
+        uint8_t GetChatContentListCount(void);
+
+        // 更新和清空问题及回答
+        bool RemoveLastTwoItemsOrClear();
+        bool UpdateUserQuestionStr(void);
+        bool UpdateAiAnswerStr(void);
+        void ClearQuestionAndAiAnswerStr(void);
+
+        // 获取和设置问题及回答
+        std::string GetUserQuestionStr(void);
+        void SetUserQuestionStr(std::string str);
+        std::string GetAiAnswerStr(void);
+        void SetAiAnswerStrStr(std::string str);
+        void SetAiAnswerStrStr(std::string str,uint8_t type);
+        uint8_t GetCurUsingAiModelType(void);
+
+        // 文件检查和AI状态管理
+        void CheckFileAndSendAIIsReady();
+        //发送AI已经就绪(继续对话时候使用)
+        void sendAIIsReady();
+
+        // AI录音路径管理
+        std::string GetAIAudioPath(void);
+
+        // 启动和停止录音
+        void StartListenAndRecordingUserQuestion(void);
+        void StopListenAndRecordingUserQuestion(void);
+
+        // 定时器管理
+        void AIVoice_StartTimer(uint32_t interval = 1000);
+        void AIVoice_StopTimer(void);
+
+        void ai_start_screen60s_timer(uint32_t interval = 30*1000);
+        void ai_stop_screen60s_timer(void);
+        void reset_ai_screen60s_timer_time();
+        bool get_screen60s_timer_is_stop(void);
+
+        void start_listening_timer(uint32_t interval = 1000);
+        void stop_listening_timer(void);
+
+        void start_ai_isready_timer(uint32_t interval = 1000);
+        void stop_ai_isready_timer(void);
+
+        void SetSelectAiModel(int index);
+        int GetSelectAiModel(void);
+        int GetAiModelTextId(void);
+
+        bool CreateDirectory(const char* path);
+
+        void SetIsClickable(bool value);
+        bool GetIsClickable(void);
+
+        void SetIsLimitDisplayed(bool value);
+        bool GetIsLimitDisplayed(void);
+
+    private:
+        AiVoiceModel();
+        ~AiVoiceModel();
+        AiVoiceModel(const AiVoiceModel &) = delete;
+        AiVoiceModel &operator=(const AiVoiceModel &) = delete;
+
+// 私有成员变量
+#if CURRENT_AIAUDIO_TYPE == AIAUDIO_TYPE_PCM
+        std::string AIAIAudioPath = "/user/userdata/AiRecording/AIAudio.pcm"; // AI录音的文件路径
+#elif CURRENT_AIAUDIO_TYPE == AIAUDIO_TYPE_SBC
+        std::string AIAIAudioPath = "/user/userdata/AiRecording/AIAudio.sbc"; // AI录音的文件路径
+#elif CURRENT_AIAUDIO_TYPE == AIAUDIO_TYPE_MSBC
+        std::string AIAIAudioPath = "/user/userdata/AiRecording/AIAudio.msbc"; // AI录音的文件路径
+#endif
+        std::string userQuestionStr;                                         // 用户提出的问题
+        std::string aiAnswerStr;                                             // AI回答的问题
+        uint8_t ChatContentListCount{0};                                     // 列表数量
+        static const uint16_t MaxChatContentListCount = 2;                   // 对话列表最大数量
+        ChatContentItem chatTtems[MaxChatContentListCount] = {0, "", false}; // 对话项数组
+        bool entryTextViewState{false};                                      // 进入返回结果界面的标志
+        std::map<int, std::pair<int, int>> selectAiModelToTextId;            // pair的参数类型<模型的textid,查询模型是否可用id>
+        bool AiVoiceConnectStatus{false};                                    //与AI模型的连接状态
+        uint8_t AIResponseType;
+        std::string errnote;                                                 //错误信息
+        int16_t curView{0};
+        bool isClickable{false};
+        bool isLimitDisplayed{false};//AI答案是否显示到极限了
+    };
+
+}
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoicePresenter.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoicePresenter.h
new file mode 100644 (file)
index 0000000..ede8f78
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-20 14:44:22
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2025-02-18 14:32:12
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AiVoicePresenter.h
+ */
+#ifndef AI_VOICE_PRESENTER_H
+#define AI_VOICE_PRESENTER_H
+
+#include "Presenter.h"
+#include "View.h"
+#include "ui_resource_string.h"
+#include "components/ui_time_picker.h"
+#include "ModelListenerSample.h"
+namespace OHOS
+{
+    class AiVoiceView;
+    class AiVoiceModel;
+    class AiVoicePresenter : public Presenter<AiVoiceView>,
+                             public UIView::OnClickListener,
+                             public UIView::OnDragListener,
+                             public RootView::OnKeyActListener,
+                             public UIPicker::SelectedListener,
+                             public UIView::OnTouchListener,
+                             public ModelListenerSample
+    {
+    public:
+        typedef enum : uint8_t
+        {
+            AIMODES_WENXINYIYAN = 0, /*文心一言*/
+            AIMODES_KIMI,            /*KIMI*/
+            AIMODES_DOUBAO,          /*豆包*/
+            AIMODES_TONGYI_QIANWEN,  /*通义千问->DeepSeek*/
+            AIMODES_IFLYTEK_SPARK,   /*讯飞星火*/
+            AIMODES_CHATGPT,         /*chatgpt*/
+            AIMODES_MAX_NUM,
+        } aimodels;
+        AiVoicePresenter();
+        virtual ~AiVoicePresenter();
+        static AiVoicePresenter *GetInstance();
+
+        void OnStart() override;
+        void OnResume() override;
+        void OnPause() override;
+        void OnStop() override;
+        void Notify() override;
+        void calculateChatContentItemViewHeight(std::string text, bool flag);
+
+        bool JumpToReturnResultTextView(void);
+        bool ChangeToAIVoiceListeningView(bool val);
+        bool ChangeToAIVoiceConnectTimeoutView();
+        bool ChangeViewAndLogicOperator(int16_t hideView, int16_t showView);
+        void FunctionKeyOnClickToChangeAIModel(void);
+        void DragLeftToRightChangeAIModel(void);
+        void DragRightToLetfChangeAIModel(void);
+
+    private:
+        bool OnClick(UIView &view, const ClickEvent &event) override;
+        bool OnPress(UIView& view, const PressEvent& event) override;
+        bool OnRelease(UIView &view, const ReleaseEvent &event) override;
+        bool OnDrag(UIView &view, const DragEvent &event) override;
+        bool OnDragEnd(UIView &view, const DragEvent &event) override;
+        bool OnKeyAct(UIView &view, const KeyEvent &event) override; // 增加按键事件
+        void OnPickerStoped(UIPicker &picker) override;
+
+        AiVoiceModel *model;
+        bool X_DRAG_FLAG{false};
+
+        int preHeight{0};
+        bool isScroll{false};
+    };
+}
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceView.h
new file mode 100644 (file)
index 0000000..9961640
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-08 09:36:01
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2025-02-18 14:48:55
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/respiratorytraining/include/AiVoiceView.h
+ */
+#ifndef AI_VOICE_VIEW_H
+#define AI_VOICE_VIEW_H
+
+
+#include "View.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_button.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_image_view.h"
+#include "components/ui_picker.h"
+#include "aivoice/include/AiVoiceBluetoothFailedStartView.h"
+#include "aivoice/include/AivoiceMobileDataFailedStartView.h"
+#include "aivoice/include/AivoiceConnectTimeoutView.h"
+#include "aivoice/include/AivoiceListeningView.h"
+#include "aivoice/include/AivoiceThinkingView.h"
+#include "aivoice/include/AivoiceReturnResultTextView.h"
+#include "aivoice/include/apikeys/SetApiKeysView.h"
+#include "aivoice/include/apikeys/NotSetApiKeysView.h"
+#include "aivoice/include/apikeys/ApiKeysDeleteView.h"
+#include "aivoice/include/AiVoiceConnectingView.h"
+#include "ui_resource_string.h"
+#include "iostream"
+#include "string"
+#include "map"
+namespace OHOS
+{
+    /*图片路径*/
+    static constexpr const char *AIMODEL_WENXINYIYAN_PATH = "/user/res/AIVoice/aimodels/aimodels_wenxinyiyan.bin";      /*文心一言*/
+    static constexpr const char *AIMODEL_CHATGPT_ON_PATH = "/user/res/AIVoice/aimodels/aimodels_chatgpt.bin";           /*ChatGPT*/
+    static constexpr const char *AIMODEL_KIMI_PATH = "/user/res/AIVoice/aimodels/aimodels_kimi.bin";                    /*KIMI*/
+    static constexpr const char *AIMODEL_DOUBAO_PATH = "/user/res/AIVoice/aimodels/aimodels_doubao.bin";                /*豆包*/
+    static constexpr const char *AIMODEL_TONGYI_QIANWEN_PATH = "/user/res/AIVoice/aimodels/aimodes_tongyi_qianwen.bin"; /*通义千问*/
+    static constexpr const char *AIMODEL_IFLYTEK_SPARK_PATH = "/user/res/AIVoice/aimodels/aimodes_iflytek_spark.bin";   /*讯飞星火*/
+    static constexpr const char *AIMODEL_DEEPSEEK_PATH = "/user/res/AIVoice/aimodels/aimodes_deepseek.bin";             /*deepseek*/
+
+    /*组件ID*/
+    static constexpr const char *AIVOICE_START_CHAT_BUTTON_VIEW_ID = "aivoice_start_chat_button_view_id"; // 开始对话
+    static constexpr const char *AIVOICE_CHAT_BUTTON_VIEW_ID = "aivoice_chat_button_view_id";             // 对话
+    static constexpr const char *AIVOICE_APIKEYS_BUTTON_VIEW_ID = "aivoice_apikeys_button_view_id";       // API Keys
+    static constexpr const char *AIVOICE_PICKER_VIEW_ID = "aivoice_picker_view_id";
+    static constexpr const char *AIVOICE_IMGAE_VIEW_ID = "aivoice_imgae_view_id";
+
+    typedef enum
+    {
+        AIVOICE_STARTCHAT_VIEWID = 0,                    // 开始对话界面
+        AIVOICE_ALERT_APPBLUETOOTH_AND_4GNETWORK_VIEWID, // APP蓝牙与4G网络都连接异常界面
+        AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID,           // 模型连接失败弹窗界面
+        AIVOICE_CONNECT_TIMEOUT_VIEWID,                  // 连接超时界面
+        AIVOICE_LISTENING_VIEWID,                        // 聆听中界面
+        AIVOICE_THINKING_VIEWID,                         // 思考中界面
+        AIVOICE_RETURN_RESULT_TEXT_VIEWID,               // 返回结果文本界面
+        AIVOICE_SETAPIKEYS,                              // API Keys set界面
+        AIVOICE_NOTSETAPIKEYS,                           // API Keys notset界面
+        AIVOICE_APIKEYS_DELETE,                          // API Keys 删除界面
+        AIVOICE_AIMODE_CONNECTING,                       // AI Mode正在连接视图
+        MAX_AIVOICE_VIEWID,
+    } AIVOICEVIEWID;
+
+    static std::map<int, const char *> TextIdToImagePath = {
+        {STR_AIMODES_WENXINYIYAN, AIMODEL_WENXINYIYAN_PATH},
+        {STR_AIMODES_KIMI, AIMODEL_KIMI_PATH},
+        {STR_AIMODELS_DOUBAO, AIMODEL_DOUBAO_PATH},
+        // {STR_TONGYI_QIANWEN, AIMODEL_TONGYI_QIANWEN_PATH},
+        {STR_DEEPSEEK, AIMODEL_DEEPSEEK_PATH},
+        {STR_IFLYTEK_SPARK, AIMODEL_IFLYTEK_SPARK_PATH},
+        {STR_AIMODES_CHATGPT, AIMODEL_CHATGPT_ON_PATH},
+    };
+
+    class AiVoicePresenter;
+    class AiVoiceView : public View<AiVoicePresenter>
+    {
+
+    public:
+        struct LabelConfig
+        {
+            int16_t left;
+            int16_t top;
+            int16_t width;
+            int16_t height;
+            int16_t fontSize;
+            int16_t lineHeigh;
+            uint16_t textId;
+            uint8_t lineBreakMode;
+        };
+
+        struct ImageConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+            const char *src;
+        };
+
+        struct ButtonConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+            const char *ViewId;
+        };
+
+        AiVoiceView();
+        ~AiVoiceView();
+        static AiVoiceView *GetInstance(void);
+        UIScrollView *GetAiVoiceScrollView(int16_t index);
+        bool ClickFunc(int16_t interface);
+        bool CheckViewParam(int16_t hideView, int16_t showView);
+        void DestroyTempView(int16_t hideView);
+        void ChangeView(int16_t hideView, int16_t showView);
+        bool ChangeAiVoiceStartChatView(int16_t thisView);
+        bool ChangeAiVoiceBluetoothFailedStartView(int16_t thisView);
+        bool ChangeAiVoiceMobileDataFailedStartView(int16_t thisView);
+        bool ChangeAiVoicConnectTimeoutView(int16_t thisView);
+        bool ChangeAiVoicListeningView(int16_t thisView);
+        bool ChangeAiVoicThinkingView(int16_t thisView);
+        bool ChangeAiVoicReturnResultTextView(int16_t thisView);
+        bool ChangeAiVoicSetApiKeysView(int16_t thisView);
+        bool ChangeAiVoicNotSetApiKeysView(int16_t thisView);
+        bool ChangeAiVoicApiKeysDeleteView(int16_t thisView);
+        bool ChangeAiVoicConnectingView(int16_t thisView);
+
+        void SetAiVoiceViewAllComponentsVisibilityStatus();
+        void ChangeAiModelAndUpdateComponentsStatus(void);
+
+        void OnStart() override;
+    
+
+    private:
+        AiVoiceBluetoothFailedStartView *p_AiVoiceBluetoothFailedStartView{nullptr};
+        AivoiceMobileDataFailedStartView *p_AivoiceMobileDataFailedStartView{nullptr};
+        AivoiceConnectTimeoutView *p_AivoiceConnectTimeoutView{nullptr};
+        AivoiceListeningView *p_AivoiceListeningView{nullptr};
+        AivoiceThinkingView *p_AivoiceThinkingView{nullptr};
+        AivoiceReturnResultTextView *p_AivoiceReturnResultTextView{nullptr};
+        SetApiKeysView *p_SetApiKeysView{nullptr};
+        NotSetApiKeysView *p_NotSetApiKeysView{nullptr};
+        ApiKeysDeleteView *p_ApiKeysDeleteView{nullptr};
+        AiVoiceConnectingView *p_AiVoiceConnectingView{nullptr};
+
+    private:
+        UILabelExt *AiVoiceViewLabelInit(LabelConfig &labelconfig);
+        UIImageView *AiVoiceViewImageView(ImageConfig &imageconfig);
+        UIButton *AiVoiceViewButtonInit(ButtonConfig &buttonconfig);
+        bool CreateAiVoiceViewLabel(void);
+        bool CreateAiVoiceViewImageView(void);
+        bool CreateAiVoiceViewButton(void);
+        bool CreateAiVoiceViewPicker(void);
+        bool CreateAiVoiceScrollView(void);
+        void CreateAiVoiceView(void);
+        void ClearAll(void);
+        void SetComponentVisibility(UIView *component, bool isVisible);
+        UILabelExt *title{nullptr};          /*标题*/
+        UILabelExt *startChatLabel{nullptr}; /*开始对话标签,暂时不用*/
+        UIButton *startChatButton{nullptr};  /*开始对话按钮*/
+        UILabelExt *chatLabel{nullptr};      /*对话标签,暂时不用*/
+        UIButton *chatButton{nullptr};       /*对话按钮*/
+        UIImageView *aiModelImage{nullptr};  /*ai模型图片*/
+        UIImageView *buttonBgImage{nullptr}; /*按钮背景图片*/
+        UIImageView *upImage{nullptr};       /*上拉箭头*/
+        UILabelExt *apiKeysLabel{nullptr};   /*API Keys标签,暂时不用*/
+        UIButton *apiKeysButton{nullptr};    /*API Keys按钮,,暂时不用*/
+        UIPicker *aiModelPicker{nullptr};    /*ai模型选择器*/
+        UIScrollView *AiVoiceScrollView[MAX_AIVOICE_VIEWID]{nullptr};
+        bool viewInitStatus{false};
+    };
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceChatContentListAdapter.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceChatContentListAdapter.h
new file mode 100644 (file)
index 0000000..f0fed05
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-03-28 14:26:55
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-07-15 20:25:36
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/languagecode/include/AivoiceChatContentListAdapter.h
+ */
+#ifndef AIVOICE_CHAT_CONTENT_LIST_ADAPTER_H
+#define AIVOICE_CHAT_CONTENT_LIST_ADAPTER_H
+
+#include "components/abstract_adapter.h"
+#include "components/ui_label_button_ext.h"
+#include "components/ui_list.h"
+#include "languagecode/LanguageInit.h"
+#include "UiConfig.h"
+#include <list>
+#include "aivoice/include/AivoiceChatContentListItemView.h"
+#include "iostream"
+
+namespace OHOS
+{
+
+    class AivoiceChatContentListAdapter : public AbstractAdapter
+    {
+    public:
+        AivoiceChatContentListAdapter();
+        ~AivoiceChatContentListAdapter();
+
+        void SetData(std::list<ChatContentItem> &data);
+        void ClearData(void);
+        std::list<ChatContentItem> &GetChatContentItem();
+        virtual uint16_t GetCount(void) override;
+        virtual UIView *GetView(UIView *inView, int16_t index) override;
+        void AddListItem(const ChatContentItem &item);
+        void SetItemClickListener(UIView::OnClickListener *itemclicklistener);
+        void calculateChatContentItemViewHeight(std::string text, bool flag);
+
+    private:
+        std::list<ChatContentItem> listData;
+        UIView::OnClickListener *itemClickListener{nullptr};
+        int itemViewHeight{0};
+        bool aiAnswerFlag{false};
+    };
+
+}
+
+#endif
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceChatContentListItemView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceChatContentListItemView.h
new file mode 100644 (file)
index 0000000..0897ec9
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-29 17:26:19
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-09-26 15:21:21
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AivoiceChatContentListItemView.h
+ */
+
+#ifndef AIVOICE_CHAT_CONTENT_LIST_ITEM_VIEW_H
+#define AIVOICE_CHAT_CONTENT_LIST_ITEM_VIEW_H
+
+#include "components/ui_view_group.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_image_view.h"
+#include "View.h"
+#include "iostream"
+#include "ChatContentItem.h"
+namespace OHOS
+{
+    class AivoiceChatContentListItemView : public UIViewGroup
+    {
+    public:
+        AivoiceChatContentListItemView(int viewHeight, bool isAiAnswerFalg);
+        ~AivoiceChatContentListItemView();
+        void SetItemInfo(const ChatContentItem &itemInfo);
+        void SetUpChild();
+        void ResetItemView(int viewHeight, bool isAiAnswerFlag);
+
+    private:
+        UILabel chatContentLabel;
+        UIImageView chatContentImage;
+        UIScrollView chatContentScrollView;
+        int m_viewHeight;
+        bool m_isAiAnswerFalg{false};
+    };
+}
+
+#endif
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceConnectTimeoutView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceConnectTimeoutView.h
new file mode 100644 (file)
index 0000000..187c2a5
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-22 16:46:26
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-08-31 16:14:01
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AivoiceConnectTimeoutView.h
+ */
+
+#ifndef AIVOICE_CONNECT_TIMEOUT_VIEW_H
+#define AIVOICE_CONNECT_TIMEOUT_VIEW_H
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_button.h"
+#include "components/ui_image_view.h"
+
+namespace OHOS
+{
+    static constexpr const char *AIVOICECONNECTTIMEOUT_ENSURE_BUTTON_VIEW_ID = "AivoiceConnectTimeoutEnsureButton"; // 连接超时界面确定按钮
+
+    class AivoiceConnectTimeoutView
+    {
+    public:
+        struct LabelConfig
+        {
+            int16_t left;
+            int16_t top;
+            int16_t width;
+            int16_t height;
+            int16_t fontSize;
+            int16_t lineHeigh;
+            uint16_t textId;
+            uint8_t lineBreakMode;
+        };
+        struct ButtonConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+            const char *ViewId;
+        };
+
+        struct ImageConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+        };
+
+        AivoiceConnectTimeoutView();
+        ~AivoiceConnectTimeoutView();
+        static AivoiceConnectTimeoutView *GetInstance(void);
+        UIScrollView *CreateAivoiceConnectTimeoutView(void);
+        void UpdateTitleTextId(int textId);
+        void UpdateNoteText();
+    private:
+        void ClearAll(void);
+        UILabelExt *AivoiceConnectTimeoutLabelInit(LabelConfig &labelconfig);
+        UIButton *AivoiceConnectTimeoutButtonInit(ButtonConfig &buttonconfig);
+        UIImageView *AivoiceConnectTimeoutImageInit(ImageConfig &imageconfig);
+        bool CreateAivoiceConnectTimeoutLabel(void);
+        bool CreateAivoiceConnectTimeoutButton(void);
+        bool CreateAivoiceConnectTimeoutImage(void);
+        bool CreateAivoiceConnectTimeoutScrollView(void);
+        UIScrollView *scrollView{nullptr};
+        UILabelExt *title{nullptr};
+        UIImageView *attentionImage{nullptr};
+        UILabelExt *NoteLabel{nullptr};
+        UILabelExt *ensure{nullptr};
+        UIButton *ensureButton{nullptr};
+    };
+}
+#endif
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceListeningView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceListeningView.h
new file mode 100644 (file)
index 0000000..d681965
--- /dev/null
@@ -0,0 +1,94 @@
+/***
+ * @Date: 2024-06-26 16:59:51
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-08-30 18:57:36
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AivoiceListeningView.h
+ */
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-22 16:46:26
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-09-25 20:34:17
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AivoiceListeningView.h
+ */
+
+#ifndef AIVOICE_LISTENING_VIEW_H
+#define AIVOICE_LISTENING_VIEW_H
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_button.h"
+#include "components/ui_image_view.h"
+#include "components/ui_image_animator.h"
+namespace OHOS
+{
+    static constexpr const char *FINISH_SPEAKING_BUTTON_VIEW_ID = "FinishSpeakingButton"; // 聆听中界面说话完毕按钮
+
+    static constexpr int16_t AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_X = 113;
+    static constexpr int16_t AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_Y = 178;
+    static constexpr int16_t AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_W = 240;
+    static constexpr int16_t AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_H = 60;
+    static constexpr int16_t AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES = 40; // 图片帧数
+    static constexpr int16_t AIVOICE_LISTENING_IMAGE_ANIMATOR_DELAY = 70;           // 图片更新间隔
+    static constexpr char *AIVoiceListeningImagePaths = "/user/res/AIVoice/AIVoiceListening/";
+    class AivoiceListeningView
+    {
+    public:
+        struct LabelConfig
+        {
+            int16_t left;
+            int16_t top;
+            int16_t width;
+            int16_t height;
+            int16_t fontSize;
+            int16_t lineHeigh;
+            uint16_t textId;
+            uint8_t lineBreakMode;
+        };
+        struct ButtonConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+            const char *ViewId;
+        };
+
+        struct ImageAnimatorConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t width;
+            int16_t height;
+            ImageAnimatorInfo *imageInfoArray;
+            const ImageInfo **pathsArray;
+            uint8_t numFrames;
+            int delay;
+        };
+
+        AivoiceListeningView();
+        ~AivoiceListeningView();
+        static AivoiceListeningView *GetInstance(void);
+        UIScrollView *CreateAivoiceListeningView(void);
+        UILabelExt *GetShowtimeoutLabel(void);
+
+    private:
+        void ClearAll(void);
+        UILabelExt *AivoiceListeningLabelInit(LabelConfig &labelconfig);
+        UIButton *AivoiceListeningButtonInit(ButtonConfig &buttonconfig);
+        UIImageAnimatorView *AivoiceListeningImageAnimatorInit(ImageAnimatorConfig &imageanimatorconfig);
+        bool CreateAivoiceListeningLabel(void);
+        bool CreateAivoiceListeningButton(void);
+        bool CreateAivoiceListeningImageAnimator(void);
+        bool CreateAivoiceListeningScrollView(void);
+        UIScrollView *scrollView{nullptr};
+        UILabelExt *title{nullptr};
+        UILabelExt *finishSpeak{nullptr};
+        UIButton *finishSpeakButton{nullptr};
+        UIImageAnimatorView *AiVoiceListeningImageAnimatorView{nullptr};
+        ImageAnimatorInfo AiVoiceListeningImageInfo[AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES];
+        const ImageInfo **AiVoiceListeningPathsArray{nullptr};
+        UILabelExt *showtimeout{nullptr};
+    };
+}
+#endif
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceMobileDataFailedStartView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceMobileDataFailedStartView.h
new file mode 100644 (file)
index 0000000..442903d
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-22 15:22:56
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-07-31 15:08:31
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AivoiceMobileDataFailedStartView.h
+ */
+
+#ifndef AIVOICE_MOBILEDATA_FAILEDSTART_VIEW_H
+#define AIVOICE_MOBILEDATA_FAILEDSTART_VIEW_H
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_button.h"
+#include "components/ui_image_view.h"
+
+namespace OHOS
+{
+    static constexpr const char *AIMODEL_CONNECT_FAILED_ENSURE_BUTTON_VIEW_ID = "AimodelConnectFailedEnsureButton_"; // 模型连接失败弹窗界面的确定按钮
+
+    class AivoiceMobileDataFailedStartView
+    {
+    public:
+        struct LabelConfig
+        {
+            int16_t left;
+            int16_t top;
+            int16_t width;
+            int16_t height;
+            int16_t fontSize;
+            int16_t lineHeigh;
+            uint16_t textId;
+            uint8_t lineBreakMode;
+        };
+        struct ButtonConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+            const char *ViewId;
+        };
+
+        struct ImageConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+        };
+
+        AivoiceMobileDataFailedStartView();
+        ~AivoiceMobileDataFailedStartView();
+        static AivoiceMobileDataFailedStartView *GetInstance(void);
+        UIScrollView *CreateAivoiceMobileDataFailedStartView(void);
+        void UpdateTitleTextId(int textId);
+
+    private:
+        void ClearAll(void);
+        UILabelExt *AivoiceMobileDataFailedStartLabelInit(LabelConfig &labelconfig);
+        UIButton *AivoiceMobileDataFailedStartButtonInit(ButtonConfig &buttonconfig);
+        UIImageView *AivoiceMobileDataFailedStartImageInit(ImageConfig &imageconfig);
+        bool CreateAivoiceMobileDataFailedStartLabel(void);
+        bool CreateAivoiceMobileDataFailedStartButton(void);
+        bool CreateAivoiceMobileDataFailedStartImage(void);
+        bool CreateAivoiceMobileDataFailedStartScrollView(void);
+        UIScrollView *scrollView{nullptr};
+        UILabelExt *title{nullptr};
+        UIImageView *attentionImage{nullptr};
+        UILabelExt *label[2]{nullptr};
+        UILabelExt *ensure{nullptr};
+        UIButton *ensureButton{nullptr};
+    };
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceReturnResultTextView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceReturnResultTextView.h
new file mode 100644 (file)
index 0000000..27d9e34
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-22 16:46:26
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2025-03-07 09:26:23
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AivoiceReturnResultTextView.h
+ */
+
+#ifndef AIVOICE_RETURN_RESULT_TEXT_VIEW_H
+#define AIVOICE_RETURN_RESULT_TEXT_VIEW_H
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_button.h"
+#include "components/ui_image_view.h"
+#include "aivoice/include/AivoiceChatContentListAdapter.h"
+#include "aivoice/include/AivoiceChatContentListItemView.h"
+namespace OHOS
+{
+    static constexpr const char *AIVOICERETURNRESULTTEXT_RETURN_BUTTON_VIEW_ID = "AivoiceReturnResultTextReturnButton";             // 返回对话内容界面的返回按钮
+    static constexpr const char *AIVOICERETURNRESULTTEXT_CONTINUECHAT_BUTTON_VIEW_ID = "AivoiceReturnResultTextContinueChatButton"; // 返回对话内容界面的继续对话按钮
+
+    class AivoiceReturnResultTextView
+    {
+    public:
+        struct LabelConfig
+        {
+            int16_t left;
+            int16_t top;
+            int16_t width;
+            int16_t height;
+            int16_t fontSize;
+            int16_t lineHeight;
+            uint16_t textId;
+            uint8_t lineBreakMode;
+        };
+        struct ButtonConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+            const char *ViewId;
+        };
+        struct ImageConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+            const char *src;
+        };
+
+        AivoiceReturnResultTextView();
+        ~AivoiceReturnResultTextView();
+        static AivoiceReturnResultTextView *GetInstance(void);
+        UIScrollView *CreateAivoiceReturnResultTextView(void);
+        void AddChatContentToList(const ChatContentItem &item);
+        AivoiceChatContentListAdapter *GetAivoiceChatContentListAdapter(void);
+        UIList *GetChatContentList(void);
+        void UpdateTitleTextId(int textId);
+        void IsScrollChatContentList(bool isScroll);
+
+    private:
+        void ClearAll(void);
+        UILabelExt *AivoiceReturnResultTextLabelInit(LabelConfig &labelconfig);
+        UIButton *AivoiceReturnResultTextButtonInit(ButtonConfig &buttonconfig);
+        UIImageView *AivoiceReturnResultTextImageInit(ImageConfig &imageconfig);
+        bool CreateAivoiceReturnResultTextLabel(void);
+        bool CreateAivoiceReturnResultTextList(void);
+        bool CreateAivoiceReturnResultTextButton(void);
+        bool CreateAivoiceReturnResultTextScrollView(void);
+        UIScrollView *scrollView{nullptr};
+        UILabelExt *title{nullptr};
+
+        UIButton *returnButton{nullptr};
+
+        UIButton *continueChatButton{nullptr};
+        UILabelExt *continueChat{nullptr};
+
+        AivoiceChatContentListAdapter *chatContentListAdapter{nullptr};
+        UIList *chatContentList{nullptr};
+    };
+}
+#endif
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceThinkingView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AivoiceThinkingView.h
new file mode 100644 (file)
index 0000000..d5b7c34
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-22 16:46:26
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-09-06 18:02:48
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AivoiceThinkingView.h
+ */
+
+#ifndef AIVOICE_THINKING_VIEW_H
+#define AIVOICE_THINKING_VIEW_H
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_button.h"
+#include "components/ui_image_view.h"
+#include "components/ui_image_animator.h"
+namespace OHOS
+{
+    static constexpr const char *CANCEL_THINKING_BUTTON_VIEW_ID = "CancelThinkingButton"; // 思考中界面取消按钮
+
+    static constexpr int16_t AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_X = 153;
+    static constexpr int16_t AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_Y = 136;
+    static constexpr int16_t AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_W = 160;
+    static constexpr int16_t AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_H = 160;
+    static constexpr int16_t AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES = 40; // 图片帧数
+    static constexpr int16_t AIVOICE_THINKING_IMAGE_ANIMATOR_DELAY = 70;          // 图片更新间隔
+    static constexpr const char *AIVoiceThinkingImagePaths = "/user/res/AIVoice/AIVoiceThinking/";
+    class AivoiceThinkingView
+    {
+    public:
+        struct LabelConfig
+        {
+            int16_t left;
+            int16_t top;
+            int16_t width;
+            int16_t height;
+            int16_t fontSize;
+            int16_t lineHeigh;
+            uint16_t textId;
+            uint8_t lineBreakMode;
+        };
+        struct ButtonConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t w;
+            int16_t h;
+            const char *ViewId;
+        };
+
+        struct ImageAnimatorConfig
+        {
+            int16_t x;
+            int16_t y;
+            int16_t width;
+            int16_t height;
+            ImageAnimatorInfo *imageInfoArray;
+            const ImageInfo **pathsArray;
+            uint8_t numFrames;
+            int delay;
+        };
+
+        AivoiceThinkingView();
+        ~AivoiceThinkingView();
+        static AivoiceThinkingView *GetInstance(void);
+        UIScrollView *CreateAivoiceThinkingView(void);
+
+    private:
+        void ClearAll(void);
+        UILabelExt *AivoiceThinkingLabelInit(LabelConfig &labelconfig);
+        UIButton *AivoiceThinkingButtonInit(ButtonConfig &buttonconfig);
+        UIImageAnimatorView *AivoiceThinkingImageAnimatorInit(ImageAnimatorConfig &imageanimatorconfig);
+        bool CreateAivoiceThinkingLabel(void);
+        bool CreateAivoiceThinkingButton(void);
+        bool CreateAivoiceThinkingImageAnimator(void);
+        bool CreateAivoiceThinkingScrollView(void);
+        UIScrollView *scrollView{nullptr};
+        UILabelExt *title{nullptr};
+        UILabelExt *cancelThink{nullptr};
+        UIButton *cancelThinkButton{nullptr};
+        UIImageAnimatorView *AiVoiceThinkingImageAnimatorView{nullptr};
+        ImageAnimatorInfo AiVoiceThinkingImageInfo[AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES];
+        const ImageInfo **AiVoiceThinkingPathsArray{nullptr};
+    };
+}
+#endif
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/ChatContentItem.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/ChatContentItem.h
new file mode 100644 (file)
index 0000000..9222a2d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-07-02 09:46:24
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-07-02 09:48:05
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/ChatContentItem.h
+ */
+#ifndef CHAT_CONTENT_ITEM_H
+#define CHAT_CONTENT_ITEM_H
+
+#include <iostream>
+#include "string"
+namespace OHOS
+{
+    typedef struct
+    {
+        int index;
+        std::string text;
+        bool isAiAnswer;
+    } ChatContentItem;
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/ApiKeysDeleteView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/ApiKeysDeleteView.h
new file mode 100644 (file)
index 0000000..38aa04b
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-07-29 16:01:34
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-07-30 15:10:06
+ * @FilePath: /xts_origin/FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/apikeys/ApiKeysDeleteView.h
+ */
+
+#ifndef APIKEYS_DELETE_VIEW_H
+#define APIKEYS_DELETE_VIEW_H
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_button.h"
+
+namespace OHOS
+{
+    static constexpr const char *APIKEYS_DELETE_BUTTON_VIEWID = "apikeys_delete_button_viewid";        /*删除APIKeys*/
+    static constexpr const char *APIKEYS_CANCEL_DELETE_BUTTON_VIEWID = "apikeys_cancel_delete_button_viewid"; /*取消删除APIkeys*/
+    static constexpr const char *APIKEYS_DELETE_SCROLLVIEW_VIEWID = "apikeys_delete_scrollview_viewid";
+
+    class ApiKeysDeleteView
+    {
+    public:
+        struct LabelConfig
+        {
+            int16_t left;
+            int16_t top;
+            int16_t width;
+            int16_t height;
+            int16_t fontSize;
+            int16_t lineHeigh;
+            uint16_t textId;
+            uint8_t lineBreakMode;
+        };
+
+        ApiKeysDeleteView();
+        ~ApiKeysDeleteView();
+        UIScrollView *CreateApiKeysDeleteView(void);
+
+    private:
+        UILabelExt *ApiKeysDeleteViewLabelInit(LabelConfig &labelconfig);
+        bool CreateApiKeysDeleteViewLabel(void);
+        void ClearAll(void);
+        UIScrollView *ApiKeysDeleteScrollView{nullptr};
+        UILabelExt *ApiKeysDeleteTitleLabel{nullptr};
+        UILabelExt *ApiKeysDeleteNoteLabel{nullptr};
+        UIButton *ApiKeysDeleteButton{nullptr};
+        UIButton *ApiKeysCancelDeleteButton{nullptr};
+        UIView::OnClickListener *clickListener{nullptr};
+        UIView::OnDragListener *dragListener{nullptr};
+    };
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/ApiKeysPresenter.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/ApiKeysPresenter.h
new file mode 100644 (file)
index 0000000..e5b7e65
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-07-29 16:14:05
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-07-29 16:24:29
+ * @FilePath: /xts_origin/FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/apikeys/ApiKeysPresenter.h
+ */
+
+#ifndef AI_MODELS_PRESENTER_H
+#define AI_MODELS_PRESENTER_H
+
+#include "View.h"
+namespace OHOS
+{
+    class ApiKeysPresenter : public UIView::OnClickListener,
+                             public UIView::OnDragListener
+    {
+    public:
+        ApiKeysPresenter();
+        virtual ~ApiKeysPresenter();
+        static ApiKeysPresenter *GetInstance();
+
+    private:
+        bool OnClick(UIView &view, const ClickEvent &event) override;
+        bool OnDrag(UIView &view, const DragEvent &event) override;
+        bool OnDragEnd(UIView &view, const DragEvent &event) override;
+
+        bool X_DRAG_FLAG{false};
+    };
+}
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/NotSetApiKeysView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/NotSetApiKeysView.h
new file mode 100644 (file)
index 0000000..3410e4b
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-07-29 16:00:52
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-07-30 09:53:04
+ * @FilePath: /xts_origin/FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/apikeys/NotNotSetApiKeysView.h
+ */
+
+#ifndef NOT_SET_APIKEYS_VIEW_H
+#define NOT_SET_APIKEYS_VIEW_H
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_button.h"
+
+namespace OHOS
+{
+    static constexpr const char *NOTSETAPIKEYS_ENSURE_BUTTON_VIEWID = "notsetapikeys_ensure_button_viewid";
+    static constexpr const char *NOTSETAPIKEYS_SCROLLVIEW_VIEWID = "notsetapikeys_scrollview_viewid";
+
+    class NotSetApiKeysView
+    {
+    public:
+        struct LabelConfig
+        {
+            int16_t left;
+            int16_t top;
+            int16_t width;
+            int16_t height;
+            int16_t fontSize;
+            int16_t lineHeigh;
+            uint16_t textId;
+            uint8_t lineBreakMode;
+        };
+
+        NotSetApiKeysView();
+        ~NotSetApiKeysView();
+        UIScrollView *CreateNotSetApiKeysView(void);
+
+    private:
+        UILabelExt *NotSetApiKeysViewLabelInit(LabelConfig &labelconfig);
+        bool CreateNotSetApiKeysViewLabel(void);
+        void ClearAll(void);
+        UIScrollView *NotSetApiKeysScrollView{nullptr};
+        UILabelExt *NotSetApiKeysTitleLabel{nullptr};
+        UILabelExt *NotSetApiKeysNoteLabel[3]{nullptr};
+        UILabelExt *NotSetApiKeysEnsureLabel{nullptr};
+        UIButton *NotSetApiKeysEnsureButton{nullptr};
+        UIView::OnClickListener *clickListener{nullptr};
+        UIView::OnDragListener *dragListener{nullptr};
+    };
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/SetApiKeysView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/apikeys/SetApiKeysView.h
new file mode 100644 (file)
index 0000000..96da534
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-07-29 16:00:31
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-07-29 18:22:38
+ * @FilePath: /xts_origin/FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/apikeys/SetApiKeysView.h
+ */
+
+#ifndef SET_APIKEYS_VIEW_H
+#define SET_APIKEYS_VIEW_H
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_image_view.h"
+#include "components/ui_button.h"
+
+namespace OHOS
+{
+    static constexpr const char *SETAPIKEYS_DELETE_BUTTON_VIEWID = "setapikeys_delete_button_viewid";
+    static constexpr const char *SETAPIKEYS_SCROLLVIEW_VIEWID = "setapikeys_scrollview_viewid";
+
+    static constexpr const char *SETAPIKEYS_IMAGE_PATH = "/user/res/AIVoice/apikey.bin";
+    class SetApiKeysView
+    {
+    public:
+        struct LabelConfig
+        {
+            int16_t left;
+            int16_t top;
+            int16_t width;
+            int16_t height;
+            int16_t fontSize;
+            int16_t lineHeigh;
+            uint16_t textId;
+            uint8_t lineBreakMode;
+        };
+
+        SetApiKeysView();
+        ~SetApiKeysView();
+        UIScrollView *CreateSetApiKeysView(void);
+
+    private:
+        UILabelExt *SetApiKeysViewLabelInit(LabelConfig &labelconfig);
+        bool CreateSetApiKeysViewLabel(void);
+        void ClearAll(void);
+        UIScrollView *SetApiKeysScrollView{nullptr};
+        UILabelExt *SetApiKeysTitleLabel{nullptr};
+        UIImageView *SetApiKeysImage{nullptr};
+        UILabelExt *SetApiKeysNoteLabel[2]{nullptr};
+        UILabelExt *SetApiKeysDeleteLabel{nullptr};
+        UIButton *SetApiKeysDeleteButton{nullptr};
+        UIView::OnClickListener *clickListener{nullptr};
+        UIView::OnDragListener *dragListener{nullptr};
+    };
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceBluetoothFailedStartView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceBluetoothFailedStartView.cpp
new file mode 100644 (file)
index 0000000..42f9829
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-05-07 11:25:58
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2025-03-03 15:10:17
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/AiVoice/src/AiVoiceBluetoothFailedStartView.cpp
+ */
+#include "aivoice/include/AiVoicePresenter.h"
+#include "aivoice/include/AiVoiceModel.h"
+#include "aivoice/include/AiVoiceBluetoothFailedStartView.h"
+#include "wearable_log.h"
+#include "ui_resource_string.h"
+#include <UiConfig.h>
+namespace OHOS
+{
+
+    static AiVoiceBluetoothFailedStartView *g_pAiVoiceBluetoothFailedStartView{nullptr};
+
+    AiVoiceBluetoothFailedStartView::AiVoiceBluetoothFailedStartView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::AiVoiceBluetoothFailedStartView");
+        g_pAiVoiceBluetoothFailedStartView = this;
+    }
+
+    AiVoiceBluetoothFailedStartView::~AiVoiceBluetoothFailedStartView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::~AiVoiceBluetoothFailedStartView");
+        ClearAll();
+        g_pAiVoiceBluetoothFailedStartView = nullptr;
+    }
+
+    AiVoiceBluetoothFailedStartView *AiVoiceBluetoothFailedStartView::GetInstance()
+    {
+        return g_pAiVoiceBluetoothFailedStartView;
+    }
+
+    void AiVoiceBluetoothFailedStartView::ClearAll(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::ClearAll");
+        if (scrollView != nullptr)
+        {
+            scrollView->RemoveAll();
+
+            if (title != nullptr)
+            {
+                delete title;
+                title = nullptr;
+            }
+
+            if (attentionImage != nullptr)
+            {
+                delete attentionImage;
+                attentionImage = nullptr;
+            }
+
+            for (int i = 0; i < (sizeof(label) / sizeof(label[0])); i++)
+            {
+                if (label[i] != nullptr)
+                {
+                    delete label[i];
+                    label[i];
+                }
+            }
+
+            if (ensure != nullptr)
+            {
+                delete ensure;
+                ensure = nullptr;
+            }
+
+            if (ensureButton != nullptr)
+            {
+                delete ensureButton;
+                ensureButton = nullptr;
+            }
+
+            delete scrollView;
+            scrollView = nullptr;
+        }
+    }
+
+    UILabelExt *AiVoiceBluetoothFailedStartView::AiVoiceBluetoothFailedStartLabelInit(LabelConfig &labelconfig)
+    {
+        UILabelExt *label = new UILabelExt();
+        if (label == nullptr)
+        {
+            return nullptr;
+        }
+        label->SetPosition(labelconfig.left, labelconfig.top, labelconfig.width, labelconfig.height);
+        label->SetStyle(STYLE_TEXT_FONT, labelconfig.fontSize);
+        label->SetStyle(STYLE_LINE_HEIGHT, labelconfig.lineHeigh);
+        //TOOD: 待优化
+        if(labelconfig.textId == STR_DEEPSEEK) {
+            label->SetText("DeepSeek");
+        } else
+            label->SetTextId(labelconfig.textId);
+        label->SetLineBreakMode(labelconfig.lineBreakMode);
+        label->SetRollSpeed(23);
+        label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, labelconfig.fontSize);
+        return label;
+    }
+
+    UIButton *AiVoiceBluetoothFailedStartView::AiVoiceBluetoothFailedStartButtonInit(ButtonConfig &buttonconfig)
+    {
+        UIButton *button = new UIButton();
+        if (button == nullptr)
+        {
+            return nullptr;
+        }
+        button->SetPosition(buttonconfig.x, buttonconfig.y, buttonconfig.w, buttonconfig.h);
+        button->SetViewId(buttonconfig.ViewId);
+        button->SetStyle(STYLE_BACKGROUND_COLOR, 0xff191919);
+        button->SetStyle(STYLE_BACKGROUND_OPA, 0xff);
+        button->SetStyleForState(STYLE_BACKGROUND_COLOR, 0xff383838, UIButton::PRESSED);
+
+        return button;
+    }
+
+    UIImageView *AiVoiceBluetoothFailedStartView::AiVoiceBluetoothFailedStartImageInit(ImageConfig &imageconfig)
+    {
+        UIImageView *Image = new UIImageView();
+        if (Image == nullptr)
+        {
+            return nullptr;
+        }
+        Image->SetPosition(imageconfig.x, imageconfig.y, imageconfig.w, imageconfig.h);
+        return Image;
+    }
+
+    bool AiVoiceBluetoothFailedStartView::CreateAiVoiceBluetoothFailedStartScrollView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::CreateAiVoiceBluetoothFailedStartScrollView");
+        scrollView = new UIScrollView();
+        if (scrollView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::scrollView new fail!");
+            return false;
+        }
+        scrollView->SetPosition(0, 0, 466, 466);
+        scrollView->SetTouchable(true);
+        scrollView->SetDraggable(true);
+        UIView::OnDragListener *dragListener = static_cast<UIView::OnDragListener *>(AiVoicePresenter::GetInstance());
+        if (dragListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::dragListener new fail!");
+            return false;
+        }
+        scrollView->SetOnDragListener(dragListener);
+        return true;
+    }
+
+    bool AiVoiceBluetoothFailedStartView::CreateAiVoiceBluetoothFailedStartLabel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::CreateAiVoiceBluetoothFailedStartLabel");
+        LabelConfig labelconfig = {
+            .left = 83,
+            .top = 50,
+            .width = 300,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = AiVoiceModel::GetInstance().GetAiModelTextId(),
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        title = AiVoiceBluetoothFailedStartLabelInit(labelconfig);
+        if (title == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::title is nullptr!");
+            return false;
+        }
+        /* -------------------------------------------------------------------------- */
+        labelconfig.left = 53;
+        labelconfig.width = 360;
+        int textId[] = {STR_BOOT_FAILED, STR_PCY4GC_OR_AS}; /*启动失败,请检查4G或打开APP连接*/
+        for (int i = 0; i < sizeof(textId) / sizeof(textId[0]); i++)
+        {
+            labelconfig.top = 222 + i * 35;
+            labelconfig.textId = textId[i];
+            label[i] = AiVoiceBluetoothFailedStartLabelInit(labelconfig);
+            if (label[i] == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::label[%d] is nullptr!", i);
+                return false;
+            }
+        }
+        /* -------------------------------------------------------------------------- */
+        labelconfig = {
+            .left = 133,
+            .top = 368,
+            .width = 200,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_OK,
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        ensure = AiVoiceBluetoothFailedStartLabelInit(labelconfig);
+        if (ensure == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::ensure is nullptr!");
+            return false;
+        }
+
+        return true;
+    }
+
+    bool AiVoiceBluetoothFailedStartView::CreateAiVoiceBluetoothFailedStartButton(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::CreateAiVoiceBluetoothFailedStartButton");
+        ButtonConfig buttonconfig = {
+            .x = 93,
+            .y = 340,
+            .w = 280,
+            .h = 90,
+            .ViewId = ALERT_APPBLUETOOTH_AND_4GNETWORK_ENSURE_BUTTON_VIEW_ID,
+        };
+        ensureButton = AiVoiceBluetoothFailedStartButtonInit(buttonconfig);
+        if (ensureButton == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ensureButton new fail!");
+            return false;
+        }
+        UIView::OnTouchListener *onReleaseListener = static_cast<UIView::OnTouchListener *>(AiVoicePresenter::GetInstance());
+        if (onReleaseListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::draglistener can not be nullptr!");
+            return false;
+        }
+        ensureButton->SetOnTouchListener(onReleaseListener);
+
+        return true;
+    }
+
+    bool AiVoiceBluetoothFailedStartView::CreateAiVoiceBluetoothFailedStartImage(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::CreateAiVoiceBluetoothFailedStartImage");
+        ImageConfig imageconfig = {
+            .x = 193,
+            .y = 120,
+            .w = 80,
+            .h = 80,
+        };
+        attentionImage = AiVoiceBluetoothFailedStartImageInit(imageconfig);
+        if (attentionImage == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "attentionImage new fail!");
+            return false;
+        }
+        attentionImage->SetStyle(STYLE_BORDER_RADIUS, 100);
+        attentionImage->SetSrc(PNG_ATTENTION_IMAGE);
+
+        return true;
+    }
+
+    UIScrollView *AiVoiceBluetoothFailedStartView::CreateAiVoiceBluetoothFailedStartView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::CreateAiVoiceBluetoothFailedStartView");
+        if (scrollView == nullptr)
+        {
+            if (!CreateAiVoiceBluetoothFailedStartScrollView() || !CreateAiVoiceBluetoothFailedStartLabel() ||
+                !CreateAiVoiceBluetoothFailedStartButton() || !CreateAiVoiceBluetoothFailedStartImage())
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::CreateAiVoiceBluetoothFailedStartView fail!!");
+                return nullptr;
+            }
+            scrollView->Add(title);
+            scrollView->Add(attentionImage);
+            scrollView->Add(label[0]);
+            scrollView->Add(label[1]);
+            scrollView->Add(ensureButton);
+            scrollView->Add(ensure);
+        }
+        return scrollView;
+    }
+
+    void AiVoiceBluetoothFailedStartView::UpdateTitleTextId(int textId)
+    {
+        if (title)
+        {
+            if(textId == STR_DEEPSEEK) 
+            {
+                title->SetText("DeepSeek");
+            } 
+            else 
+            {
+            title->SetTextId(textId);
+            title->ForceResetText();
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceConnectingView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceConnectingView.cpp
new file mode 100644 (file)
index 0000000..98b314e
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-08-03 11:10:08
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-11-05 11:08:54
+ * @FilePath: /xts_origin/FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/src/AiVoiceConnectingView.cpp
+ */
+#include "aivoice/include/AiVoiceConnectingView.h"
+#include "aivoice/include/AiVoicePresenter.h"
+#include "wearable_log.h"
+#include "ui_resource_string.h"
+#include "common/image_cache_manager.h"
+#include "uicomponents/UIComponents.h"
+#include "uiservice/include/ui_service.h"
+namespace OHOS
+{
+    static constexpr int16_t AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_X = 183;
+    static constexpr int16_t AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_Y = 153;
+    static constexpr int16_t AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_W = 100;
+    static constexpr int16_t AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_H = 120;
+    static constexpr int16_t AIVOICE_CONNECTING_IMAGE_ANIMATOR_DELAY = 50; // 图片更新间隔
+    static constexpr const char *AIVoiceListeningImagePaths = "/user/res/connect/";
+
+    static AiVoiceConnectingView *g_pAiVoiceConnecting{nullptr};
+    AiVoiceConnectingView::AiVoiceConnectingView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::AiVoiceConnectingView");
+        g_pAiVoiceConnecting = this;
+    }
+
+    AiVoiceConnectingView::~AiVoiceConnectingView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::~AiVoiceConnectingView");
+        ClearAll();
+        g_pAiVoiceConnecting = nullptr;
+    }
+
+    void AiVoiceConnectingView::ClearAll(void)
+    {
+        if (scrollView != nullptr)
+        {
+            scrollView->RemoveAll();
+            if (title)
+            {
+                delete title;
+                title = nullptr;
+            }
+            if (connectingAnimatorView)
+            {
+                connectingAnimatorView->Stop();
+                delete connectingAnimatorView;
+                connectingAnimatorView = nullptr;
+                FreeImageInfoArray(connectingPathsArray, AIVoiceListeningImagePaths, AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES);
+            }
+            if (cancelLabel)
+            {
+                delete cancelLabel;
+                cancelLabel = nullptr;
+            }
+            if (cancelButton != nullptr)
+            {
+                delete cancelButton;
+                cancelButton = nullptr;
+            }
+
+            delete scrollView;
+            scrollView = nullptr;
+        }
+        ScreenTurnOff();
+    }
+
+    AiVoiceConnectingView *AiVoiceConnectingView::GetInstance(void)
+    {
+        return g_pAiVoiceConnecting;
+    }
+
+    UILabelExt *AiVoiceConnectingView::AiVoiceConnectingViewLabelInit(LabelConfig &labelconfig)
+    {
+        UILabelExt *label = new UILabelExt();
+        if (label == nullptr)
+        {
+            return nullptr;
+        }
+        label->SetPosition(labelconfig.left, labelconfig.top, labelconfig.width, labelconfig.height);
+        label->SetStyle(STYLE_TEXT_FONT, labelconfig.fontSize);
+        label->SetStyle(STYLE_LINE_HEIGHT, labelconfig.lineHeigh);
+        label->SetTextId(labelconfig.textId);
+        label->SetLineBreakMode(labelconfig.lineBreakMode);
+        label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label->SetRollSpeed(23);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, labelconfig.fontSize);
+        return label;
+    }
+
+    UIButton *AiVoiceConnectingView::AiVoiceConnectingViewButtonInit(ButtonConfig &buttonconfig)
+    {
+        UIButton *button = new UIButton();
+        if (button == nullptr)
+        {
+            return nullptr;
+        }
+        button->SetPosition(buttonconfig.x, buttonconfig.y, buttonconfig.w, buttonconfig.h);
+        button->SetViewId(buttonconfig.viewId);
+        button->SetStyle(STYLE_BACKGROUND_COLOR, 0xff191919);
+        button->SetStyle(STYLE_BACKGROUND_OPA, 0xff);
+        button->SetStyleForState(STYLE_BACKGROUND_COLOR, 0xff383838, UIButton::PRESSED);
+
+        return button;
+    }
+
+    UIImageAnimatorView *AiVoiceConnectingView::connectingImageAnimatorInit(ImageAnimatorConfig &imageanimatorconfig)
+    {
+        UIImageAnimatorView *animatorView = new UIImageAnimatorView();
+        if (animatorView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceListeningImageAnimatorView::AiVoiceListeningImageAnimatorView new fail");
+            return nullptr;
+        }
+
+        for (uint8_t i = 0; i < imageanimatorconfig.numFrames; i++)
+        {
+            imageanimatorconfig.imageInfoArray[i].imageInfo = (imageanimatorconfig.pathsArray[i]);
+            imageanimatorconfig.imageInfoArray[i].imageType = IMG_SRC_IMAGE_INFO;
+            // imageanimatorconfig.imageInfoArray[i].imagePath = (imageanimatorconfig.pathsArray[i]);
+            // imageanimatorconfig.imageInfoArray[i].imageType = IMG_SRC_FILE_PATH;
+            imageanimatorconfig.imageInfoArray[i].pos.x = imageanimatorconfig.x;
+            imageanimatorconfig.imageInfoArray[i].pos.y = imageanimatorconfig.y;
+            imageanimatorconfig.imageInfoArray[i].width = imageanimatorconfig.width;
+            imageanimatorconfig.imageInfoArray[i].height = imageanimatorconfig.height;
+        }
+
+        animatorView->SetPosition(imageanimatorconfig.x, imageanimatorconfig.y, imageanimatorconfig.width, imageanimatorconfig.height);
+        animatorView->SetImageAnimatorSrc(imageanimatorconfig.imageInfoArray, imageanimatorconfig.numFrames, imageanimatorconfig.delay);
+        animatorView->SetRepeat(true);
+        animatorView->SetSizeFixed(true);
+        // animatorView->SetAutoEnable(false);
+        // animatorView->SetResizeMode(UIImageAnimatorView::FILL);
+        animatorView->Start();
+
+        return animatorView;
+    }
+
+    bool AiVoiceConnectingView::CreateAiVoiceConnectingViewLabel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingViewLabel");
+        LabelConfig labelConfig = {
+            .left = 83,
+            .top = 50,
+            .width = 300,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_CONNECTING,
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        if (title == nullptr)
+        {
+            title = AiVoiceConnectingViewLabelInit(labelConfig);
+            if (title == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "title new fail!");
+                return false;
+            }
+        }
+        /* -------------------------------------------------------------------------- */
+        labelConfig = {
+            .left = 133,
+            .top = 368,
+            .width = 200,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_CANCEL,
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        if (cancelLabel == nullptr)
+        {
+            cancelLabel = AiVoiceConnectingViewLabelInit(labelConfig);
+            if (cancelLabel == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceBluetoothFailedStartView::cancelLabel is nullptr!");
+                return false;
+            }
+            cancelLabel->SetTextColor(Color::GetColorFromRGBA(0xfd, 0x52, 0x13, 0xff));
+        }
+
+        return true;
+    }
+
+    bool AiVoiceConnectingView::CreateAiVoiceConnectingViewButton(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingViewButton");
+        ButtonConfig buttonconfig = {
+            .x = 93,
+            .y = 340,
+            .w = 280,
+            .h = 90,
+            .viewId = AIVOICECONNECTINGVIEW_CANCEL_BUTTON_VIEW_ID,
+        };
+        if (cancelButton == nullptr)
+        {
+            cancelButton = AiVoiceConnectingViewButtonInit(buttonconfig);
+            if (cancelButton == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "cancelButton new fail!");
+                return false;
+            }
+        }
+        UIView::OnTouchListener *touchListener = static_cast<UIView::OnTouchListener *>(AiVoicePresenter::GetInstance());
+        if (touchListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::touchListener can not be nullptr!");
+            return false;
+        }
+        cancelButton->SetOnTouchListener(touchListener);
+
+        return true;
+    }
+
+    bool AiVoiceConnectingView::CreateAivoiceConnectingImageAnimator(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAivoiceConnectingImageAnimator");
+        if (connectingPathsArray == nullptr)
+        {
+            connectingPathsArray = CreateImageInfoArray(AIVoiceListeningImagePaths, AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES);
+            if (connectingPathsArray == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::connectingPathsArray  is nullptr!!");
+                return false;
+            }
+        }
+
+        ImageAnimatorConfig imageanimatorconfig = {
+            .x = AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_X,
+            .y = AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_Y,
+            .width = AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_W,
+            .height = AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_H,
+            .imageInfoArray = connectingImageInfo,
+            .pathsArray = connectingPathsArray,
+            .numFrames = AIVOICE_CONNECTING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES,
+            .delay = AIVOICE_CONNECTING_IMAGE_ANIMATOR_DELAY,
+        };
+        if (connectingAnimatorView == nullptr)
+        {
+            connectingAnimatorView = connectingImageAnimatorInit(imageanimatorconfig);
+            if (connectingAnimatorView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::connectingAnimatorView new fail");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    bool AiVoiceConnectingView::CreateAiVoiceConnectingScrollView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingScrollView");
+        if (scrollView == nullptr)
+        {
+            scrollView = new UIScrollView();
+            if (scrollView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::scrollView new fail!");
+                return false;
+            }
+        }
+        UIView::OnDragListener *dragListener = static_cast<UIView::OnDragListener *>(AiVoicePresenter::GetInstance());
+        if (dragListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::dragListener new fail!");
+            return false;
+        }
+        scrollView->SetOnDragListener(dragListener);
+        scrollView->SetPosition(0, 0, 466, 466);
+        scrollView->SetTouchable(true);
+        scrollView->SetDraggable(true);
+
+        return true;
+    }
+
+    bool AiVoiceConnectingView::CreateAiVoiceConnectingScrollView(uint8_t type)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingScrollView");
+        if (scrollView == nullptr)
+        {
+            scrollView = new UIScrollView();
+            if (scrollView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::scrollView new fail!");
+                return false;
+            }
+        }
+        scrollView->SetPosition(0, 0, 466, 466);
+        scrollView->SetTouchable(true);
+        scrollView->SetDraggable(true);
+
+        return true;
+    }
+
+    UIScrollView *AiVoiceConnectingView::CreateAiVoiceConnectingView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingView");
+#if 0
+        if (!CreateAiVoiceConnectingScrollView() || !CreateAivoiceConnectingImageAnimator() || !CreateAiVoiceConnectingViewLabel() || !CreateAiVoiceConnectingViewButton())
+        {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingView fail!!");
+            return nullptr;
+        }
+        scrollView->Add(title);
+        scrollView->Add(connectingAnimatorView);
+        scrollView->Add(cancelButton);
+        scrollView->Add(cancelLabel);
+
+        return scrollView;
+#else
+        if (!CreateAiVoiceConnectingScrollView())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingScrollView fail!!");
+        }
+        if (!CreateAivoiceConnectingImageAnimator())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAivoiceConnectingImageAnimator fail!!");
+        }
+        if (!CreateAiVoiceConnectingViewLabel())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingViewLabel fail!!");
+        }
+        if (!CreateAiVoiceConnectingViewButton())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingViewButton fail!!");
+        }
+
+#endif
+        if (scrollView == nullptr)
+        {
+            return nullptr;
+        }
+        else
+        {
+            if (title)
+            {
+                scrollView->Add(title);
+            }
+            if (connectingAnimatorView)
+            {
+                scrollView->Add(connectingAnimatorView);
+            }
+            if (cancelButton)
+            {
+                scrollView->Add(cancelButton);
+            }
+            if (cancelLabel)
+            {
+                scrollView->Add(cancelLabel);
+            }
+            return scrollView;
+        }
+    }
+
+    UIScrollView *AiVoiceConnectingView::CreateAiVoiceConnectingView(uint8_t type)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingView");
+#if 0
+        if (!CreateAiVoiceConnectingScrollView(type) || !CreateAivoiceConnectingImageAnimator() || !CreateAiVoiceConnectingViewLabel())
+        {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingView fail!!");
+            return nullptr;
+        }
+        connectingAnimatorView->SetPosition(183, 183);
+        connectingAnimatorView->Invalidate();
+        ScreenTurnOn(30 * 1000); // 亮屏30s
+        scrollView->Add(connectingAnimatorView);
+#else
+        if (!CreateAiVoiceConnectingScrollView(type))
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingScrollView fail!!");
+        }
+        if (!CreateAivoiceConnectingImageAnimator())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAivoiceConnectingImageAnimator fail!!");
+        }
+        if (!CreateAiVoiceConnectingViewLabel())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceConnectingView::CreateAiVoiceConnectingViewLabel fail!!");
+        }
+        if (scrollView == nullptr)
+        {
+            return nullptr;
+        }
+        else
+        {
+            if (connectingAnimatorView)
+            {
+                connectingAnimatorView->SetPosition(183, 183);
+                connectingAnimatorView->Invalidate();
+                scrollView->Add(connectingAnimatorView);
+            }
+            ScreenTurnOn(30 * 1000); // 亮屏30s
+            return scrollView;
+        }
+#endif
+    }
+
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp
new file mode 100644 (file)
index 0000000..3cdf4ef
--- /dev/null
@@ -0,0 +1,1151 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-20 15:14:50
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2025-03-19 11:09:58
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/src/AiVoiceModel.cpp
+ */
+#include "aivoice/include/AiVoiceModel.h"
+#include "aivoice/include/AiVoicePresenter.h"
+#include "aivoice/include/AiVoiceView.h"
+#include "aivoice/include/AivoiceReturnResultTextView.h"
+#include "wearable_log.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cmsis_os2.h>
+#include <cmsis_os.h>
+#include <ohos_types.h>
+#include <service/graphic_service.h>
+#include <iostream>
+#include "uiservice/include/ui_service.h"
+#include <custom_utils.h>
+#ifdef SUPPORT_BLE_SERVICE
+#include <bleEvent.h>
+#include "bleService.h"
+#endif
+#include <unistd.h>
+#include "ConfigModel.h"
+#include "settings/include/SettingModel.h"
+#include <unistd.h>
+#include <sys/stat.h>
+#include <custom_save_runtime.h>
+namespace OHOS
+{
+    // 声明定时器变量
+    static osTimerId_t g_timer = nullptr;
+    static constexpr uint16_t THIRTY_TIME = 30 / 3;
+    static int Time = THIRTY_TIME;
+    static int AiModelConnectTimeout = 5;
+
+    AiVoiceModel::AiVoiceModel()
+    {
+        CreateDirectory("/user/userdata/AiRecording/");
+    }
+
+    AiVoiceModel::~AiVoiceModel() {}
+
+    AiVoiceModel &AiVoiceModel::GetInstance()
+    {
+        static AiVoiceModel instance;
+        return instance;
+    }
+
+    bool AiVoiceModel::CreateDirectory(const char *path)
+    {
+        if (access(path, F_OK) == -1)
+        { // 如果路径不存在
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Directory %s not exist, creating directory\n", path);
+            if (mkdir(path, 0777) != 0)
+            { // 尝试创建目录,如果创建失败
+                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Create directory %s failed\n", path);
+                return false;
+            }
+        }
+        else
+        { // 如果路径存在
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Directory %s already exists\n", path);
+        }
+        return true;
+    }
+
+    // 跳转到返回结果界面
+    bool AiVoiceModel::ChangeToReturnResultTextView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ChangeToReturnResultTextView");
+        AiVoicePresenter *Aipresenter_ = AiVoicePresenter::GetInstance();
+        if (Aipresenter_ == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ChangeToReturnResultTextView fail!!");
+            return false;
+        }
+        Aipresenter_->JumpToReturnResultTextView();
+        entryTextViewState = false;
+        return true;
+    }
+
+    /*跳转到AI聆听界面界面*/
+    bool AiVoiceModel::ChangeToAIVoiceListeningView(bool value)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ChangeToAIVoiceListeningView");
+        AiVoicePresenter *Aipresenter_ = AiVoicePresenter::GetInstance();
+        if (Aipresenter_ == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ChangeToAIVoiceListeningView fail!!");
+            return false;
+        }
+        Aipresenter_->ChangeToAIVoiceListeningView(value);
+        return true;
+    }
+
+    // 切换到AI回应错误界面
+    bool AiVoiceModel::ChangeToAIVoiceConnectTimeoutView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ChangeToAIVoiceConnectTimeoutView");
+        AiVoicePresenter *Aipresenter_ = AiVoicePresenter::GetInstance();
+        if (Aipresenter_ == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::GetInstance() fail!!");
+            return false;
+        }
+        Aipresenter_->ChangeToAIVoiceConnectTimeoutView();
+        return true;
+    }
+
+    // 功能键切换模型
+    void AiVoiceModel::FunctionKeyOnClickToChangeAIModel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::FunctionKeyOnClickToChangeAIModel");
+        AiVoicePresenter *Aipresenter_ = AiVoicePresenter::GetInstance();
+        if (Aipresenter_ == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::FunctionKeyOnClickToChangeAIModel fail!!");
+            return;
+        }
+        Aipresenter_->FunctionKeyOnClickToChangeAIModel();
+        return;
+    }
+
+    /*获取API Keys是否可用*/
+    bool AiVoiceModel::IsExistOpenAIAPIKeys()
+    {
+        bool flag;
+        if (ConfigModel::GetInstance()->GetOpenAIAPIKeys() == "-1")
+        {
+            flag = false;
+        }
+        else
+        {
+            flag = true;
+        }
+        return flag;
+    }
+
+    /*删除本地的API Keys*/
+    void AiVoiceModel::DeleteLocalOpenAIAPIKeys()
+    {
+        ConfigModel::GetInstance()->SetOpenAIAPIKeys("-1");
+    }
+
+    // 获取APP蓝牙是否已连接
+    bool AiVoiceModel::GetAPPBluetoothIsConnect(void)
+    {
+        // return SettingModel::GetInstance().GetPhoneConnectStatus();
+
+        #ifdef SUPPORT_BLE_SERVICE
+        return get_ble_connect();
+        #else
+        return false;   
+        #endif
+    }
+
+    // 获取4G网络是否正常
+    bool AiVoiceModel::GetMobileDataIsOpen(void)
+    {
+        return false;
+    }
+
+    /*查询用户选择的AI模型是否已经连接*/
+    void AiVoiceModel::QuerySelectedAiModelIsConnect()
+    {
+        #ifdef SUPPORT_BLE_SERVICE
+        auto it = selectAiModelToTextId.find(GetSelectAiModel());
+        if (it != selectAiModelToTextId.end())
+        {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "[QuerySelectedAiModelIsConnect] SelectAiModel = %d", it->second.second);
+            inquire_AI_is_ready(it->second.second);
+        }
+        #endif
+    }
+
+    // 获取当前正在使用的AI模型
+    uint8_t AiVoiceModel::GetCurUsingAiModelType(void){
+    
+        auto it = selectAiModelToTextId.find(GetSelectAiModel());
+        if (it != selectAiModelToTextId.end())
+        {
+            return it->second.second;
+        }
+        return 0;
+    }
+
+    /*取消当前AI对话*/
+    void AiVoiceModel::CancelCurAIChat(void)
+    {
+        // cancel_AI_cur_chat(); //线程发送取消当前对话
+        #ifdef SUPPORT_BLE_SERVICE
+        cancel_AI_cur_chat_();// 直接发送取消当前对话
+        #endif
+    }
+
+    int AiVoiceModel::GetAIResponseType(void)
+    {
+        return AIResponseType;
+    }
+
+    std::string AiVoiceModel::GetErrnote(void)
+    {
+        return errnote;
+    }
+
+    void AiVoiceModel::SetErrnote(std::string str)
+    {
+        errnote = str;
+    }
+
+    /*设置当前哪个子视图是可见的*/
+    void AiVoiceModel::SetCurView(int16_t viewNum)
+    {
+        curView = viewNum;
+    }
+
+    /*获取当前哪个子视图是可见的*/
+    int AiVoiceModel::GetCurView(void)
+    {
+        return curView;
+    }
+
+    /*列表数量*/
+    uint8_t AiVoiceModel::GetChatContentListCount(void)
+    {
+        return ChatContentListCount;
+    }
+
+    /*添加聊天内容项到数组*/
+    bool AiVoiceModel::AddChatContentToItemArray(const ChatContentItem &item)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ChatContentListCount = %d", ChatContentListCount);
+        // 检查 ChatContentListCount 是否超出范围
+        if (ChatContentListCount >= MaxChatContentListCount)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ChatContentListCount out of bounds!!");
+            return false;
+        }
+
+        chatTtems[ChatContentListCount] = item;
+        ChatContentListCount++;
+
+        return true;
+    }
+
+    /*添加用户问题项*/
+    bool AiVoiceModel::AddUserQuestionToChatItems()
+    {
+        ChatContentItem UserQuestionStrItem;
+        UserQuestionStrItem.index = GetChatContentListCount();
+        UserQuestionStrItem.text = GetUserQuestionStr();
+        UserQuestionStrItem.isAiAnswer = false;
+        return AddChatContentToItemArray(UserQuestionStrItem);
+    }
+
+    /*添加AI回答项*/
+    bool AiVoiceModel::AddAiAnswerToChatItems()
+    {
+        ChatContentItem AiAnswerStrItem;
+        AiAnswerStrItem.index = GetChatContentListCount();
+        AiAnswerStrItem.text = GetAiAnswerStr();
+        AiAnswerStrItem.isAiAnswer = true;
+        return AddChatContentToItemArray(AiAnswerStrItem);
+    }
+
+    /*初始化历史对话数据*/
+    bool AiVoiceModel::InitchatContentItems(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::InitchatContentItems");
+
+        // 获取单例对象
+        AivoiceReturnResultTextView *p_AivoiceReturnResultTextView = AivoiceReturnResultTextView::GetInstance();
+        if (p_AivoiceReturnResultTextView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::GetInstance fail!!");
+            return false;
+        }
+
+        // 添加用户问题项到数组
+        if (!AddUserQuestionToChatItems())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AddUserQuestionToChatItems fail!!");
+            return false;
+        }
+
+        // 添加AI回答项到数组
+        if (!AddAiAnswerToChatItems())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AddAiAnswerToChatItems fail!!");
+            return false;
+        }
+
+        // 将聊天内容添加到显示列表中
+        for (uint8_t i = 0; i < ChatContentListCount; i++)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "chatTtems[%d]", i);
+            p_AivoiceReturnResultTextView->AddChatContentToList(chatTtems[i]);
+        }
+
+        // 更新显示列表
+        auto chatContentListAdapter = p_AivoiceReturnResultTextView->GetAivoiceChatContentListAdapter();
+        auto chatContentList = p_AivoiceReturnResultTextView->GetChatContentList();
+        if (chatContentListAdapter != nullptr && chatContentList != nullptr)
+        {
+            chatContentList->SetAdapter(chatContentListAdapter);
+            // chatContentList->RefreshList();
+        }
+        else
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Chat content list or adapter is nullptr!!");
+            return false;
+        }
+
+        return true;
+    }
+
+    // 函数定义:移除列表的最后两项或清空列表
+    bool AiVoiceModel::RemoveLastTwoItemsOrClear()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::RemoveLastTwoItemsOrClear");
+        AivoiceReturnResultTextView *p_AivoiceReturnResultTextView = AivoiceReturnResultTextView::GetInstance();
+        if (p_AivoiceReturnResultTextView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::GetInstance fail!!");
+            return false;
+        }
+        // 获取适配器
+        AivoiceChatContentListAdapter *adapter = p_AivoiceReturnResultTextView->GetAivoiceChatContentListAdapter();
+        if (adapter != nullptr)
+        {
+            // 获取列表的大小
+            size_t listSize = adapter->GetChatContentItem().size();
+
+            // 移除最后两项或清空列表
+            if (listSize >= 2)
+            {
+                auto it = adapter->GetChatContentItem().end();
+                std::advance(it, -2); // 移动迭代器到倒数第二项的位置
+                adapter->GetChatContentItem().erase(it, adapter->GetChatContentItem().end());
+            }
+            else if (listSize == 1)
+            {
+                // 如果列表只有一项,直接清空
+                adapter->GetChatContentItem().clear();
+            }
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "listSize = %d", listSize);
+            ChatContentListCount -= (listSize < 2 ? listSize : 2);
+        }
+        return true;
+    }
+
+    /* 更新用户问题字符串 */
+    bool AiVoiceModel::UpdateUserQuestionStr()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::UpdateUserQuestionStr");
+
+        if(!RemoveLastTwoItemsOrClear())
+        {
+            return false;
+        }
+        
+        if (!AddUserQuestionToChatItems())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AddUserQuestionToChatItems fail!!");
+            return false;
+        }
+
+        // 更新显示列表
+        AivoiceReturnResultTextView *p_AivoiceReturnResultTextView = AivoiceReturnResultTextView::GetInstance();
+        if (!p_AivoiceReturnResultTextView)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::GetInstance fail!!");
+            return false;
+        }
+
+        AivoiceChatContentListAdapter *adapter = static_cast<AivoiceChatContentListAdapter *>(p_AivoiceReturnResultTextView->GetAivoiceChatContentListAdapter());
+        if (adapter)
+        {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GetChatContentListCount() - 1 = %d,line =%d", GetChatContentListCount() - 1, __LINE__);
+            adapter->GetChatContentItem().push_back(chatTtems[GetChatContentListCount() - 1]);
+            p_AivoiceReturnResultTextView->GetChatContentList()->RefreshList();
+        }
+        else
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Chat content adapter is nullptr!!");
+            return false;
+        }
+
+        return true;
+    }
+
+    /*更新Ai答案字符串*/
+    bool AiVoiceModel::UpdateAiAnswerStr()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::UpdateAiAnswerStr");
+        #if 0
+        AiVoiceView *view_ = AiVoiceView::GetInstance();
+        if(view_!= nullptr )
+        {
+            if(view_->GetAiVoiceScrollView(AIVOICE_RETURN_RESULT_TEXT_VIEWID) && !view_->GetAiVoiceScrollView(AIVOICE_RETURN_RESULT_TEXT_VIEWID)->IsVisible())
+            {
+                return false;
+            }
+            else
+            {
+                if(!GetIsClickable())
+                {
+                    SetIsClickable(true);
+                }
+            }
+        }
+        #endif
+
+        int index = GetChatContentListCount() - 1;
+        if (index < 0 || index >= MaxChatContentListCount)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid index: %d", index);
+            return false;
+        }
+
+        if (chatTtems[index].isAiAnswer) // 处理ai1的多段回答
+        {
+            ChatContentListCount--;
+        }
+
+        if (!AddAiAnswerToChatItems())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AddAiAnswerToChatItems fail!!");
+            return false;
+        }
+
+        // 更新显示列表
+        AivoiceReturnResultTextView *p_AivoiceReturnResultTextView = AivoiceReturnResultTextView::GetInstance();
+        if (!p_AivoiceReturnResultTextView)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::GetInstance fail!!");
+            return false;
+        }
+
+        AivoiceChatContentListAdapter *adapter = static_cast<AivoiceChatContentListAdapter *>(p_AivoiceReturnResultTextView->GetAivoiceChatContentListAdapter());
+        if (adapter != nullptr && !adapter->GetChatContentItem().empty())
+        {
+            // 如果最后一条是 AI 回答,则移除
+            if (adapter->GetChatContentItem().back().isAiAnswer)
+            {
+                adapter->GetChatContentItem().pop_back();
+            }
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GetChatContentListCount() - 1 = %d,line = %d", GetChatContentListCount() - 1, __LINE__);
+            // 将更新后的 AI 回答内容添加到列表
+            adapter->GetChatContentItem().push_back(chatTtems[GetChatContentListCount() - 1]);
+            if (AiVoicePresenter::GetInstance())
+                AiVoicePresenter::GetInstance()->calculateChatContentItemViewHeight(chatTtems[GetChatContentListCount() - 1].text, true); 
+            p_AivoiceReturnResultTextView->GetChatContentList()->RefreshList();
+        }
+        else
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Chat content adapter is nullptr!!");
+            return false;
+        }
+
+        return true;
+    }
+
+    void AiVoiceModel::SetIsClickable(bool value)
+    {
+        isClickable = value;
+    }
+    
+    bool AiVoiceModel::GetIsClickable(void)
+    {
+        return isClickable;
+    }
+
+    void AiVoiceModel::SetIsLimitDisplayed(bool value)
+    {
+        isLimitDisplayed = value;
+    }
+    bool AiVoiceModel::GetIsLimitDisplayed(void)
+    {
+        return isLimitDisplayed;
+    }
+
+    /*获取用户问题的字符串*/
+    std::string AiVoiceModel::GetUserQuestionStr(void)
+    {
+        // userQuestionStr = "写一篇100字文章";
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GetUserQuestionStr:%s\n", userQuestionStr.c_str());
+        return userQuestionStr;
+    }
+
+    /*设置用户问题的字符串*/
+    void AiVoiceModel::SetUserQuestionStr(std::string str)
+    {
+        if (!entryTextViewState)
+        {
+            #ifdef SUPPORT_BLE_SERVICE
+            //SendMsgToUIService(UI_AI_JUMP_TO_RESULT_VIEW, 0, nullptr, 0);
+            #endif
+            entryTextViewState = true; // 进入返回结果界面的标志  避免重复发消息
+            usleep(50000);             // 延时等待创建完成,0.05秒
+        }
+        /* -------------------------------------------------------------------------- */
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "传入的问题:%s",str.c_str());
+        userQuestionStr = str;
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "拼接的问题:%s",userQuestionStr.c_str());
+        /* -------------------------------------------------------------------------- */
+        #ifdef SUPPORT_BLE_SERVICE
+        //SendMsgToUIService(UI_UPDATE_USER_QUESTION_STR, 0, nullptr, 0);
+        #endif
+    }
+
+    /*获取Ai回答的字符串*/
+    std::string AiVoiceModel::GetAiAnswerStr(void)
+    {
+        // aiAnswerStr = "春风化雨,时光荏苒。百年之内,生命如白驹过隙,转瞬即逝。唯有心存善念,用爱化解芥蒂,用智慧建构未来,才是人生的真正意义。让我们携手共进,用每一分时光去关爱他人,用每一滴汗水去创造奇迹,用每一个眼神去传递温暖。让这个世界因我们的存在而变得更加美好。生命短暂,但只要我们怀着虔诚的心,坚韧前行,我们就一定能在有限的时光里留下无限的可能。";
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GetAiAnswerStr:%s", aiAnswerStr.c_str());
+        return aiAnswerStr;
+    }
+
+    /*设置Ai回答的字符串*/
+    void AiVoiceModel::SetAiAnswerStrStr(std::string str)
+    {
+        aiAnswerStr += str;
+        //SendMsgToUIService(UI_UPDATE_AI_ANSWER_STR, 0, nullptr, 0);
+    }
+
+    void AiVoiceModel::SetAiAnswerStrStr(std::string str, uint8_t type)
+    {
+        AIResponseType = type;
+        errnote = str;
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AIResponseType = %d,errnote = %s\n", AIResponseType, errnote.c_str());
+        //如果是:AI录音解析错误或AI 回应错误 ,或者重传多次录音数据->跳转AI回应错误界面
+        if (AIResponseType == AiVoiceModel::AI_RECORDING_PARSING_ERROR || AIResponseType == AiVoiceModel::AI_RESPONSE_ERROR 
+            || AIResponseType == AiVoiceModel::AI_BLE_ERROR)
+        {
+            //SendMsgToUIService(UI_AI_JUMP_TO_RESPONDERR_VIEW, 0, (void *)errnote.c_str(), errnote.length());
+            return;
+        }
+        else if (AiVoiceModel::AI_RESPONSE_END) // 如果是AI 回应结束
+        {
+            if (errnote.empty()) // 如果没有回应数据
+            {
+                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::GetErrnote is empty!!");
+                AiVoiceModel::GetInstance().SetErrnote("响应内容为空");
+                std::string str = AiVoiceModel::GetInstance().GetErrnote();
+                //SendMsgToUIService(UI_AI_JUMP_TO_RESPONDERR_VIEW, 0, (void *)str.c_str(), str.length());
+                return;
+            }
+        }
+        AiVoiceView *view_ = AiVoiceView::GetInstance();
+        if(view_!= nullptr )
+        {
+            if(view_->GetAiVoiceScrollView(AIVOICE_RETURN_RESULT_TEXT_VIEWID) && view_->GetAiVoiceScrollView(AIVOICE_RETURN_RESULT_TEXT_VIEWID)->IsVisible())
+            {
+                if(!OHOS::AiVoiceModel::GetInstance().GetIsLimitDisplayed()) //如果ai答案没有显示到极限了,就更新ai答案字符串
+                { 
+                    aiAnswerStr += str;
+                    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "接受字的符串:%s", aiAnswerStr.c_str());
+                    //SendMsgToUIService(UI_UPDATE_AI_ANSWER_STR, 0, nullptr, 0);
+                }
+            }
+        }
+    }
+
+    /*清空上次用户问题和Ai回答字符串*/
+    void AiVoiceModel::ClearQuestionAndAiAnswerStr(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "清空上次用户问题和Ai回答字符串");
+        userQuestionStr = "";
+        aiAnswerStr = "";
+    }
+
+    /*获取AI音频路径*/
+    std::string AiVoiceModel::GetAIAudioPath(void)
+    {
+        return AIAIAudioPath;
+    }
+
+#ifdef __cplusplus
+    extern "C"
+    {
+#endif
+        int32_t AudioCaptureSample(int32_t argc, const char *argv[]);
+        int32_t streamingRecordAndSend_AI(int type);
+        #define IS_SUPPORT_REALTIME_RECORD_SEND_AI 1 //是否支持实时发送录音数据
+#ifdef __cplusplus
+    };
+#endif
+
+    // 开始聆听并录取用户问题
+    void AiVoiceModel::StartListenAndRecordingUserQuestion(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "聆听用户问题并发送录音数据");
+        AiVoiceView *view_ = AiVoiceView::GetInstance();
+        if (view_ == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceView::GetInstance fail!!");
+            return;
+        }
+        if ((view_->GetAiVoiceScrollView(AIVOICE_LISTENING_VIEWID) != nullptr) &&
+            (view_->GetAiVoiceScrollView(AIVOICE_LISTENING_VIEWID)->IsVisible()))
+        {
+#if IS_SUPPORT_REALTIME_RECORD_SEND_AI
+            int type = GetCurUsingAiModelType();
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "type = %d", type);
+            #ifdef SUPPORT_BLE_SERVICE
+            streamingRecordAndSend_AI(type);//实时发送录音数据
+            #endif
+#else
+            std::string audioPath = AiVoiceModel::GetInstance().GetAIAudioPath();
+            if (uapi_delete_files(audioPath.c_str())) // 先删除文件
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uapi_delete_files,%s", audioPath.c_str());
+            }
+            else
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uapi_delete_files fail!!");
+            }
+#if CURRENT_AIAUDIO_TYPE == AIAUDIO_TYPE_PCM
+            const char *defaultArgs[6] = {"01", "pcm", "16000", "1", "16", audioPath.c_str()};
+#elif CURRENT_AIAUDIO_TYPE == AIAUDIO_TYPE_SBC
+            const char *defaultArgs[6] = {"01", "sbc", "16000", "1", "16", audioPath.c_str()};
+#elif CURRENT_AIAUDIO_TYPE == AIAUDIO_TYPE_MSBC
+            const char *defaultArgs[6] = {"01", "msbc", "16000", "1", "16", audioPath.c_str()};
+#endif
+            uapi_save_runtime_log(RUNTIME_LOG_RECORD_START_AI);//TOOD*
+            AudioCaptureSample(6, (const char **)defaultArgs);            
+#endif
+        }
+        return;
+    }
+
+    // 停止聆听用户问题
+    void AiVoiceModel::StopListenAndRecordingUserQuestion(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "停止录音");
+        int32_t argc = 1;
+        uint8_t *argv = (uint8_t *)"stop";
+        AudioCaptureSample(argc, (const char **)&argv);
+        uapi_save_runtime_log(RUNTIME_LOG_RECORD_STOP_AI);//TOOD*
+        return;
+    }
+
+    /*检查录音文件是否存在并发送语音准备操作*/
+    void AiVoiceModel::CheckFileAndSendAIIsReady(void)
+    {
+        #ifdef SUPPORT_BLE_SERVICE
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::CheckFileAndSendAIIsReady");
+        const std::string &filePath = AIAIAudioPath;
+        FILE *file = fopen(filePath.c_str(), "r");
+        if (file != nullptr)
+        {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "File already exists: %s", filePath.c_str());
+
+            fseek(file, 0, SEEK_END);
+            long size = ftell(file);
+            fseek(file, 0, SEEK_SET);
+            if (size != 0)
+            {
+                auto it = selectAiModelToTextId.find(GetSelectAiModel());
+                if (it != selectAiModelToTextId.end())
+                {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "filesize = %ld,SelectAiModel = %d", size, it->second.second);
+                    if(get_ble_interval() >= BLE_CONNECT_INTERVAL_SLOW)
+                    {
+                        uapi_ble_connect_param_update(BLE_CONNECT_INTERVAL_HIGH);
+                    }
+                    send_AI_is_ready(it->second.second);
+                }
+                else
+                {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GetSelectAiModel fail!!", size, it->second.second);
+                }
+
+                ClearQuestionAndAiAnswerStr(); // 清空上次用户问题和Ai回答字符串
+            }
+            fclose(file);
+        }
+        else
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "File does not exist: %s", filePath.c_str());
+            // Handle the case where the file doesn't exist, if needed
+        }
+        #endif
+    }
+
+    void AiVoiceModel::sendAIIsReady()
+    {
+        #ifdef SUPPORT_BLE_SERVICE
+        auto it = selectAiModelToTextId.find(GetSelectAiModel());
+        if (it != selectAiModelToTextId.end())
+        {
+            // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "filesize = %ld,SelectAiModel = %d", size, it->second.second);
+            if(get_ble_interval() >= BLE_CONNECT_INTERVAL_SLOW)
+            {
+                uapi_ble_connect_param_update(BLE_CONNECT_INTERVAL_HIGH);
+            }
+            send_AI_is_ready(it->second.second);
+        }
+        #endif
+    }
+
+    void AiVoiceModel::StatusResume(void)
+    {
+        Time = THIRTY_TIME;
+        AiModelConnectTimeout = 5;
+        AiVoiceConnectStatus = false;
+
+        for (int i = 0; i < ChatContentListCount; i++)
+        {
+            chatTtems[i].index = 0;
+            chatTtems[i].text = "";
+            chatTtems[i].isAiAnswer = false;
+        }
+        ChatContentListCount = 0;
+        entryTextViewState = false;
+        isClickable = false;
+        isLimitDisplayed = false;
+        ClearQuestionAndAiAnswerStr();
+        StopListenAndRecordingUserQuestion();
+    }
+
+    /* -------------------------------------------------------------------------- */
+    /*定时器到期时的处理*/
+    static void AIVoice_TimerCallbackProc(int data)
+    {
+        // 等待AI思考完成的定时器
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AIVoice_TimerCallbackProc,Time = %d", Time);
+        if (Time < 0) // 如果思考时间超时30s,进入连接超时界面
+        {
+            AiVoiceModel::GetInstance().AIVoice_StopTimer();
+            AiVoiceModel::GetInstance().SetErrnote("连接超时,请重新开始对话");
+            std::string str = AiVoiceModel::GetInstance().GetErrnote();
+            //SendMsgToUIService(UI_AI_JUMP_TO_RESPONDERR_VIEW, 0, (void *)str.c_str(), str.length());
+        }
+        else
+        {
+            #ifdef SUPPORT_BLE_SERVICE
+            // 4g中途断连待扩展
+            // 蓝牙的连接状态判断,如果AI思考过程中途断连,直接弹窗提示,不在硬等
+            if (get_ble_connect() == false)
+            {
+                AiVoiceModel::GetInstance().SetErrnote("手机蓝牙已断开");
+                std::string str = AiVoiceModel::GetInstance().GetErrnote();
+                SendMsgToUIService(UI_AI_JUMP_TO_RESPONDERR_VIEW, 0, (void *)str.c_str(), str.length());
+            }
+            #endif
+        }
+        return;
+    }
+
+    /*
+     * @brief 回调函数
+     */
+    static void AIVoice_TimerCallback(int data)
+    {
+        Time -= 1;
+        GraphicService::GetInstance()->PostGraphicEvent(std::bind(AIVoice_TimerCallbackProc, data));
+    }
+
+    /*
+     *  @brief 开启定时器函数
+     *  @param interval 时间间隔,单位ms
+     */
+    void AiVoiceModel::AIVoice_StartTimer(uint32_t interval)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::AIVoice_StartTimer");
+        /* -------------------------- 1.检查定时器是否已经存在,如果存在则返回 ------------------------- */
+        if (g_timer != nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer already exists!!");
+            return;
+        }
+
+        /* --------------------------------- 2.创建定时器 -------------------------------- */
+        g_timer = osTimerNew((osTimerFunc_t)AIVoice_TimerCallback, osTimerPeriodic, nullptr, nullptr);
+        // 检查定时器创建是否成功
+        if (g_timer == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer create failed!!");
+            return;
+        }
+
+        /* ----------------------------- 3.将毫秒转换为系统时钟节拍数 ---------------------------- */
+        int tick = osMs2Tick(interval);
+
+        /* --------------------------------- 4.启动定时器 -------------------------------- */
+        osStatus_t ret = osTimerStart(g_timer, tick);
+        /* -------------------- 5.检查定时器启动是否成功,如果启动失败,删除定时器并置为 nullptr -------------------- */
+        if (ret != osOK)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret);
+            if (g_timer != nullptr)
+            {
+                ret = osTimerDelete(g_timer);
+            }
+            g_timer = nullptr;
+            return;
+        }
+    }
+
+    /*
+     * @brief 停止定时器
+     */
+    void AiVoiceModel::AIVoice_StopTimer(void)
+    {
+        // 检查定时器是否存在
+        if (g_timer != nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::AIVoice_StopTimer");
+            osTimerStop(g_timer);
+            // 删除定时器并置为 nullptr
+            osStatus_t ret = osTimerDelete(g_timer);
+            if (ret != osOK)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret);
+            }
+            g_timer = nullptr;
+            Time = THIRTY_TIME;
+            AiModelConnectTimeout = 5;
+        }
+    }
+
+    // 声明定时器变量
+    static osTimerId_t g_screen60s_timer = nullptr;
+    static int8_t SCREEN_60S_TIME = 60; // 60s
+
+    static void ai_start_screen60s_timer_callbackProc(int data)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ai_start_screen60s_timer_callbackProc,time = %d", SCREEN_60S_TIME);
+        SCREEN_60S_TIME -= 30;
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ai_start_screen60s_timer_callbackProc,time = %d", SCREEN_60S_TIME);
+        if (SCREEN_60S_TIME <= 0)
+        {
+            // 60s后息屏停止定时
+            AiVoiceModel::GetInstance().ai_stop_screen60s_timer();
+            // 取消常亮屏
+            ScreenAlwaysOnCtr(CANCEL_SCREEN_ALWAYS_ON);
+        }
+    }
+    static void ai_start_screen60s_timer_callback(int data)
+    {
+        // GraphicService::GetInstance()->PostGraphicEvent(std::bind(ai_start_screen60s_timer_callbackProc, data));
+        ai_start_screen60s_timer_callbackProc(data);
+    }
+    void AiVoiceModel::ai_start_screen60s_timer(uint32_t interval)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ai_start_screen60s_timer");
+        /* -------------------------- 1.检查定时器是否已经存在,如果存在则返回 ------------------------- */
+        if (g_screen60s_timer != nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer already exists!!");
+            return;
+        }
+        /* --------------------------------- 2.创建定时器 -------------------------------- */
+        g_screen60s_timer = osTimerNew((osTimerFunc_t)ai_start_screen60s_timer_callback, osTimerPeriodic, nullptr, nullptr);
+        // 检查定时器创建是否成功
+        if (g_screen60s_timer == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer create failed!!");
+            return;
+        }
+        /* ----------------------------- 3.将毫秒转换为系统时钟节拍数 ---------------------------- */
+        int tick = osMs2Tick(interval);
+        /* --------------------------------- 4.启动定时器 -------------------------------- */
+        osStatus_t ret = osTimerStart(g_screen60s_timer, tick);
+        /* -------------------- 5.检查定时器启动是否成功,如果启动失败,删除定时器并置为 nullptr -------------------- */
+        if (ret != osOK)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret);
+            if (g_screen60s_timer != nullptr)
+            {
+                ret = osTimerDelete(g_screen60s_timer);
+            }
+            g_screen60s_timer = nullptr;
+            return;
+        }
+    }
+    void AiVoiceModel::ai_stop_screen60s_timer(void)
+    {
+        // 检查定时器是否存在
+        if (g_screen60s_timer != nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ai_stop_screen60s_timer");
+            osTimerStop(g_screen60s_timer);
+            // 删除定时器并置为 nullptr
+            osStatus_t ret = osTimerDelete(g_screen60s_timer);
+            if (ret != osOK)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret);
+            }
+            g_screen60s_timer = nullptr;
+            SCREEN_60S_TIME = 60;
+        }
+    }
+    void AiVoiceModel::reset_ai_screen60s_timer_time()
+    {
+        SCREEN_60S_TIME = 60;
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "reset_ai_screen60s_timer_time %d", SCREEN_60S_TIME);
+        if (nullptr == g_screen60s_timer)
+        {
+            ScreenAlwaysOnCtr(OPEN_SCREEN_ALWAYS_ON); // 重新常亮屏
+            ai_start_screen60s_timer();               // 开启定时器
+        }
+    }
+
+    bool AiVoiceModel::get_screen60s_timer_is_stop(void)
+    {
+        if(g_screen60s_timer == nullptr)
+            return true;
+        else
+            return false;
+    }
+    static osTimerId_t g_listeningEndHandle = nullptr;
+    static int8_t LISTENING_TIMEOUT = 10; // 10s钟无操作关闭该视图
+    static void AIListeningCallbackProc(int data)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AIListeningCallbackProc %d", LISTENING_TIMEOUT);
+        LISTENING_TIMEOUT--;
+        if (LISTENING_TIMEOUT <= 0)
+        {
+            AiVoiceModel::GetInstance().StopListenAndRecordingUserQuestion(); // 停止聆听用户问题
+            AiVoiceModel::GetInstance().stop_listening_timer();               // 停止聆听定时器
+            if (AiVoiceView::GetInstance() && AivoiceListeningView::GetInstance())
+            {
+                AiVoiceView::GetInstance()->ChangeView(AIVOICE_LISTENING_VIEWID, AIVOICE_THINKING_VIEWID); // 切换到思考中界面
+                AiVoiceModel::GetInstance().AIVoice_StartTimer();
+            }
+        }
+        else
+        {
+            if (AivoiceListeningView::GetInstance())
+            {
+                AivoiceListeningView::GetInstance()->GetShowtimeoutLabel()->SetText(std::to_string(LISTENING_TIMEOUT).c_str());
+                AivoiceListeningView::GetInstance()->GetShowtimeoutLabel()->Invalidate();
+            }
+        }
+        return;
+    }
+    static void AIListeningCallback(int data)
+    {
+        GraphicService::GetInstance()->PostGraphicEvent(std::bind(AIListeningCallbackProc, data));
+    }
+    // 开启一个AI录音的定时器
+    void AiVoiceModel::start_listening_timer(uint32_t interval)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::start_listening_timer");
+        /* -------------------------- 1.检查定时器是否已经存在,如果存在则返回 ------------------------- */
+        if (g_listeningEndHandle != nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer already exists!!");
+            return;
+        }
+        /* --------------------------------- 2.创建定时器 -------------------------------- */
+        g_listeningEndHandle = osTimerNew((osTimerFunc_t)AIListeningCallback, osTimerPeriodic, nullptr, nullptr);
+        // 检查定时器创建是否成功
+        if (g_listeningEndHandle == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer create failed!!");
+            return;
+        }
+        /* ----------------------------- 3.将毫秒转换为系统时钟节拍数 ---------------------------- */
+        int tick = osMs2Tick(interval);
+        /* --------------------------------- 4.启动定时器 -------------------------------- */
+        osStatus_t ret = osTimerStart(g_listeningEndHandle, tick);
+        /* -------------------- 5.检查定时器启动是否成功,如果启动失败,删除定时器并置为 nullptr -------------------- */
+        if (ret != osOK)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret);
+            if (g_listeningEndHandle != nullptr)
+            {
+                ret = osTimerDelete(g_listeningEndHandle);
+            }
+            g_listeningEndHandle = nullptr;
+            return;
+        }
+    }
+
+    // 停止一个AI录音的定时器
+    void AiVoiceModel::stop_listening_timer(void)
+    {
+        // 检查定时器是否存在
+        if (g_listeningEndHandle != nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::stop_listening_timer");
+            osTimerStop(g_listeningEndHandle);
+            // 删除定时器并置为 nullptr
+            osStatus_t ret = osTimerDelete(g_listeningEndHandle);
+            if (ret != osOK)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret);
+            }
+            g_listeningEndHandle = nullptr;
+            LISTENING_TIMEOUT = 10;
+        }
+    }
+
+    static osTimerId_t g_ai_is_ready_Handle = nullptr; // 处理查询AI是否就绪定时器
+    static int8_t AI_IS_READY_TIMEOUT = 5;            // 5s钟超时
+    static void AI_IS_READY_CallbackProc(int data)
+    {
+        if (AI_IS_READY_TIMEOUT <= 0) // 模型连接失败有5秒超时
+        {
+            AiVoiceModel::GetInstance().stop_ai_isready_timer();
+            AiVoiceView *view_ = AiVoiceView::GetInstance();
+            AiVoicePresenter *p_AiVoicePresenter = AiVoicePresenter::GetInstance();
+            if (view_ != nullptr && p_AiVoicePresenter != nullptr)
+            {
+                if ((view_->GetAiVoiceScrollView(AIVOICE_AIMODE_CONNECTING) != nullptr) &&
+                    (view_->GetAiVoiceScrollView(AIVOICE_AIMODE_CONNECTING)->IsVisible()))
+                {
+                    p_AiVoicePresenter->ChangeViewAndLogicOperator(AIVOICE_AIMODE_CONNECTING, AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID);
+                }
+            }
+        }
+        return;
+    }
+    static void AI_IS_READY_Callback(int data)
+    {
+        AI_IS_READY_TIMEOUT--;
+        GraphicService::GetInstance()->PostGraphicEvent(std::bind(AI_IS_READY_CallbackProc, data));
+    }
+
+    // 开启一个查询AI是否准备就绪的定时器
+    void AiVoiceModel::start_ai_isready_timer(uint32_t interval)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::start_ai_isready_timer");
+        /* -------------------------- 1.检查定时器是否已经存在,如果存在则返回 ------------------------- */
+        if (g_ai_is_ready_Handle != nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer already exists!!");
+            return;
+        }
+        /* --------------------------------- 2.创建定时器 -------------------------------- */
+        g_ai_is_ready_Handle = osTimerNew((osTimerFunc_t)AI_IS_READY_Callback, osTimerPeriodic, nullptr, nullptr);
+        // 检查定时器创建是否成功
+        if (g_ai_is_ready_Handle == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer create failed!!");
+            return;
+        }
+        /* ----------------------------- 3.将毫秒转换为系统时钟节拍数 ---------------------------- */
+        int tick = osMs2Tick(interval);
+        /* --------------------------------- 4.启动定时器 -------------------------------- */
+        osStatus_t ret = osTimerStart(g_ai_is_ready_Handle, tick);
+        /* -------------------- 5.检查定时器启动是否成功,如果启动失败,删除定时器并置为 nullptr -------------------- */
+        if (ret != osOK)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret);
+            if (g_ai_is_ready_Handle != nullptr)
+            {
+                ret = osTimerDelete(g_ai_is_ready_Handle);
+            }
+            g_ai_is_ready_Handle = nullptr;
+            return;
+        }
+        return;
+    }
+
+    // 停止一个查询AI是否准备就绪的定时器
+    void AiVoiceModel::stop_ai_isready_timer(void)
+    {
+        // 检查定时器是否存在
+        if (g_ai_is_ready_Handle != nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::stop_ai_isready_timer");
+            osTimerStop(g_ai_is_ready_Handle);
+            // 删除定时器并置为 nullptr
+            osStatus_t ret = osTimerDelete(g_ai_is_ready_Handle);
+            if (ret != osOK)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret);
+            }
+            g_ai_is_ready_Handle = nullptr;
+            AI_IS_READY_TIMEOUT = 5;
+        }
+    }
+
+    // 设置选择的ai模型
+    void AiVoiceModel::SetSelectAiModel(int index)
+    {
+        ConfigModel::GetInstance()->SetSelectAiModel(index);
+    }
+
+    int AiVoiceModel::GetSelectAiModel(void)
+    {
+        return ConfigModel::GetInstance()->GetSelectAiModel();
+    }
+
+    /*获取已选择的ai模型的textid*/
+    int AiVoiceModel::GetAiModelTextId()
+    {
+        #if 0
+        int language = ConfigModel::GetInstance()->GetLanguage();
+        int textId;
+
+        if (language == 0)
+        {
+            selectAiModelToTextId = {
+                {0, {STR_AIMODES_WENXINYIYAN, 0}},
+                {1, {STR_AIMODES_KIMI, 2}},
+                {2, {STR_AIMODELS_DOUBAO, 3}},
+                // {3, {STR_TONGYI_QIANWEN, 4}},
+                {3, {STR_DEEPSEEK, 4}},
+                {4, {STR_IFLYTEK_SPARK, 5}},
+                {5, {STR_AIMODES_CHATGPT, 1}},
+            };
+            textId = STR_AIMODES_WENXINYIYAN;
+        }
+        else
+        {
+            selectAiModelToTextId = {
+                {0, {STR_AIMODES_CHATGPT, 1}},
+                {1, {STR_AIMODES_WENXINYIYAN, 0}},
+                {2, {STR_AIMODES_KIMI, 2}},
+                {3, {STR_AIMODELS_DOUBAO, 3}},
+                // {4, {STR_TONGYI_QIANWEN, 4}},
+                {4, {STR_DEEPSEEK, 4}},
+                {5, {STR_IFLYTEK_SPARK, 5}},
+            };
+            textId = STR_AIMODES_CHATGPT;
+        }
+        #endif
+        //客户新需求需要改模型顺序:
+        int textId = 0;
+        selectAiModelToTextId = {
+            {0, {STR_DEEPSEEK, 4}},
+            {1, {STR_AIMODES_CHATGPT, 1}},
+            {2, {STR_AIMODELS_DOUBAO, 3}},
+            {3, {STR_AIMODES_WENXINYIYAN, 0}},
+            {4, {STR_AIMODES_KIMI, 2}},
+            {5, {STR_IFLYTEK_SPARK, 5}},
+        };
+        textId = STR_DEEPSEEK;
+
+        // 根据视图ID设置文本ID
+        auto it = selectAiModelToTextId.find(GetSelectAiModel());
+        if (it != selectAiModelToTextId.end())
+        {
+            return it->second.first;
+        }
+
+        return textId;
+    }
+
+}
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoicePresenter.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoicePresenter.cpp
new file mode 100644 (file)
index 0000000..cfdcb8c
--- /dev/null
@@ -0,0 +1,587 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-20 15:11:17
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2025-03-19 10:24:14
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/src/AiVoicePresenter.cpp
+ */
+#include "AppViewIDs.h"
+#include "NativeAbility.h"
+#include "aivoice/include/AiVoicePresenter.h"
+#include "aivoice/include/AiVoiceView.h"
+#include "aivoice/include/AiVoiceModel.h"
+#include "common/key_code.h"
+#include <custom_utils.h>
+#include "UiConfig.h"
+#include "iostream"
+#include <string>        // For std::string
+#include <unordered_map> // For std::unordered_map
+#include <string>        // For std::string
+#include <unordered_map> // For std::unordered_map
+
+#ifdef SUPPORT_BLE_SERVICE
+#include <bleEvent.h>
+#include "bleService.h"
+#endif
+
+#include <unistd.h>
+#include "gfx_utils/mem_check.h"
+
+#include "player/include/PlayersModel.h"
+
+#include "NativeRegisterManager.h"
+namespace OHOS
+{
+
+    REGIST_MENU_PRO(VIEW_AI_VOICE, AiVoiceView, AiVoicePresenter,
+        PNG_APPLIST_AIVOICE_IMAGE_BIG, PNG_APPLIST_AIVOICE_IMAGE,PNG_APPLIST_AIVOICE_IMAGE, "AI全家桶", STR_AI_FAMILY_MEALS);
+
+#define BLE_CONNECT_INTERVAL_HIGH_AI 10
+    // 当前Presenter属性实例化的内存指针
+    static AiVoicePresenter *g_pAiVoicePresenter = nullptr;
+
+    AiVoicePresenter::AiVoicePresenter()
+    {
+#ifdef MEM_CHECK
+        MemCheck::GetInstance()->EnableLeakCheck(true);
+#endif
+        model = &AiVoiceModel::GetInstance();
+        g_pAiVoicePresenter = this;
+    }
+
+    AiVoicePresenter::~AiVoicePresenter()
+    {
+#ifdef MEM_CHECK
+        MemCheck::GetInstance()->EnableLeakCheck(false);
+#endif
+        g_pAiVoicePresenter = nullptr;
+    }
+
+    AiVoicePresenter *AiVoicePresenter::GetInstance()
+    {
+        return g_pAiVoicePresenter;
+    }
+
+    // 启动时执行的逻辑
+    void AiVoicePresenter::OnStart()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::OnStart");
+        Presenter<AiVoiceView>::OnStart();
+        ScreenAlwaysOnCtr(OPEN_SCREEN_ALWAYS_ON);
+        // 开启一个60s取消长亮屏timer
+        model->ai_start_screen60s_timer();
+#ifdef SUPPORT_BLE_SERVICE
+        uapi_ble_connect_param_update(BLE_CONNECT_INTERVAL_HIGH_AI);
+#endif
+    }
+
+    // 页面已经展示后的调用逻辑
+    void AiVoicePresenter::OnResume(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::OnResume");
+        Presenter<AiVoiceView>::OnResume();
+        if (view_ == nullptr)
+        {
+            return;
+        }
+    }
+
+    // 页面准备切换到后台前执行的逻辑
+    void AiVoicePresenter::OnPause(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::OnPause");
+        Presenter<AiVoiceView>::OnPause();
+    }
+
+    // 页面完全置于后台时的逻辑。
+    void AiVoicePresenter::OnStop(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::OnStop");
+        Presenter<AiVoiceView>::OnStop();
+        ScreenAlwaysOnCtr(CANCEL_SCREEN_ALWAYS_ON);
+        model->StatusResume();
+        model->AIVoice_StopTimer();
+        model->ai_stop_screen60s_timer();
+        model->stop_listening_timer();
+        model->stop_ai_isready_timer();
+        #ifdef SUPPORT_BLE_SERVICE
+        uapi_ble_connect_param_update(BLE_CONNECT_INTERVAL_SLOW);
+        #endif
+    }
+
+    /*调转到返回结果界面*/
+    bool AiVoicePresenter::JumpToReturnResultTextView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::JumpToReturnResultTextView");
+        if (view_->GetAiVoiceScrollView(AIVOICE_THINKING_VIEWID) != nullptr &&
+            view_->GetAiVoiceScrollView(AIVOICE_THINKING_VIEWID)->IsVisible())
+        {
+            preHeight = 0;
+            ChangeViewAndLogicOperator(AIVOICE_THINKING_VIEWID, AIVOICE_RETURN_RESULT_TEXT_VIEWID);
+        }
+        else
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::JumpToReturnResultTextView fail");
+            return false;
+        }
+        return true;
+    }
+
+    /*跳转到AI聆听界面界面*/
+    bool AiVoicePresenter::ChangeToAIVoiceListeningView(bool val)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::ChangeToAIVoiceListeningView");
+        if (view_->GetAiVoiceScrollView(AIVOICE_AIMODE_CONNECTING) != nullptr && view_->GetAiVoiceScrollView(AIVOICE_AIMODE_CONNECTING)->IsVisible())
+        {
+            model->stop_ai_isready_timer(); // 停止定时器
+            if (val)                        /*如果查询的AI模型可用跳转到聆听中界面*/
+            {
+                ChangeViewAndLogicOperator(AIVOICE_AIMODE_CONNECTING, AIVOICE_LISTENING_VIEWID);
+            }
+            else
+            {
+                if(model->GetAiModelTextId() == STR_AIMODES_CHATGPT) //如果当前是在chatgpt模型*/
+                {
+                    ChangeViewAndLogicOperator(AIVOICE_AIMODE_CONNECTING, AIVOICE_NOTSETAPIKEYS); /*开始对话界面->API Keys notset界面*/
+                }
+                else
+                {
+                    ChangeViewAndLogicOperator(AIVOICE_AIMODE_CONNECTING, AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID);
+                }
+            }
+        }
+        else
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::ChangeToAIVoiceListeningView fail");
+            return false;
+        }
+        return true;
+    }
+
+    bool AiVoicePresenter::ChangeToAIVoiceConnectTimeoutView()
+    {
+        if ((view_->GetAiVoiceScrollView(AIVOICE_THINKING_VIEWID) != nullptr) &&
+            (view_->GetAiVoiceScrollView(AIVOICE_THINKING_VIEWID)->IsVisible()))
+        {
+            ChangeViewAndLogicOperator(AIVOICE_THINKING_VIEWID, AIVOICE_CONNECT_TIMEOUT_VIEWID);
+            AivoiceConnectTimeoutView *p_AivoiceConnectTimeoutView = AivoiceConnectTimeoutView::GetInstance();
+            if (p_AivoiceConnectTimeoutView)
+            {
+                p_AivoiceConnectTimeoutView->UpdateNoteText();
+            }
+        }
+        return true;
+    }
+
+    void AiVoicePresenter::FunctionKeyOnClickToChangeAIModel(void)
+    {
+        if(view_->GetAiVoiceScrollView(AIVOICE_STARTCHAT_VIEWID) && view_->GetAiVoiceScrollView(AIVOICE_STARTCHAT_VIEWID)->IsVisible() == true)
+        {
+            int index = model->GetSelectAiModel() + 1;
+            if (index >= AIMODES_MAX_NUM)
+            {
+                index = 0;
+            }
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiModelsPresenter::index = %d", index);
+            model->SetSelectAiModel(index);
+            view_->ChangeAiModelAndUpdateComponentsStatus();
+            model->reset_ai_screen60s_timer_time(); // 重置60s取消常亮屏timer
+        }
+        return;
+    }
+
+    // 右滑切换模型
+    void AiVoicePresenter::DragLeftToRightChangeAIModel(void)
+    {
+        if(view_->GetAiVoiceScrollView(AIVOICE_STARTCHAT_VIEWID) && view_->GetAiVoiceScrollView(AIVOICE_STARTCHAT_VIEWID)->IsVisible() == true)
+        {
+            int index = model->GetSelectAiModel() + 1;
+            if (index >= AIMODES_MAX_NUM)
+            {
+                index = 0;
+            }
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiModelsPresenter::index = %d", index);
+            model->SetSelectAiModel(index);
+            view_->ChangeAiModelAndUpdateComponentsStatus();
+        }
+        return;
+    }
+
+    // 左滑切换模型
+    void AiVoicePresenter::DragRightToLetfChangeAIModel(void)
+    {
+        if(view_->GetAiVoiceScrollView(AIVOICE_STARTCHAT_VIEWID) && view_->GetAiVoiceScrollView(AIVOICE_STARTCHAT_VIEWID)->IsVisible() == true)
+        {
+            int index = model->GetSelectAiModel() - 1;
+            if (index < 0)
+            {
+                index = AIMODES_CHATGPT;
+            }
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiModelsPresenter::index = %d", index);
+            model->SetSelectAiModel(index);
+            view_->ChangeAiModelAndUpdateComponentsStatus();
+        }
+        return;
+    }
+
+    bool AiVoicePresenter::ChangeViewAndLogicOperator(int16_t hideView, int16_t showView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::ChangeViewOperator");
+
+        if (hideView > MAX_AIVOICE_VIEWID)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Overstep ones bounds");
+            return false;
+        }
+
+        /* ------------------------ 进行界面切换的时候重置60s取消常亮屏timer ------------------------ */
+        model->reset_ai_screen60s_timer_time();
+        /* -------------------------------------------------------------------------- */
+        view_->ChangeView(hideView, showView); // 默认先进行视图切换
+
+        switch (hideView)
+        {
+        case AIVOICE_STARTCHAT_VIEWID:
+            model->QuerySelectedAiModelIsConnect(); /*查询用户选择的AI模型是否已经连接*/
+            if (showView == AIVOICE_LISTENING_VIEWID)
+            {
+                model->StartListenAndRecordingUserQuestion();
+            }
+            else if (showView == AIVOICE_AIMODE_CONNECTING)
+            {
+                model->start_ai_isready_timer(); /*开启一个查询AI模型是否连接成功定时器*/
+            }
+            break;
+
+        case AIVOICE_AIMODE_CONNECTING:
+            if (showView == AIVOICE_LISTENING_VIEWID)
+            {
+                model->StartListenAndRecordingUserQuestion();
+            }
+            break;
+
+        case AIVOICE_LISTENING_VIEWID:
+            model->StopListenAndRecordingUserQuestion();
+            model->stop_listening_timer();
+            if (showView == AIVOICE_THINKING_VIEWID) // 聆听中->思考中界面
+            {
+                model->AIVoice_StartTimer();
+            }
+            break;
+
+        case AIVOICE_THINKING_VIEWID:
+            model->AIVoice_StopTimer();
+            break;
+
+        case AIVOICE_RETURN_RESULT_TEXT_VIEWID:
+            AiVoiceModel::GetInstance().ClearQuestionAndAiAnswerStr(); // 清空上次用户问题和Ai回答字符串
+            AiVoiceModel::GetInstance().SetIsClickable(false);
+            AiVoiceModel::GetInstance().SetIsLimitDisplayed(false);
+            if (showView == AIVOICE_LISTENING_VIEWID)
+            {
+                model->StartListenAndRecordingUserQuestion();
+            }
+            break;
+
+        default:
+            // Handle other cases if needed
+            break;
+        }
+
+        return true;
+    }
+
+    // 处理手点击屏幕切换AI模型
+    bool AiVoicePresenter::OnClick(UIView &view, const ClickEvent &event)
+    {
+        UNUSED(event);
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::OnClick");
+
+        model->reset_ai_screen60s_timer_time(); // 重置60s取消常亮屏timer
+
+        if (strcmp(view.GetViewId(), AIVOICE_IMGAE_VIEW_ID) == 0) /*点击的是Ai模型就切换模型*/
+        {
+            int index = model->GetSelectAiModel() + 1;
+            if (index >= AIMODES_MAX_NUM)
+            {
+                index = 0;
+            }
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiModelsPresenter::index = %d", index);
+            model->SetSelectAiModel(index);
+            view_->ChangeAiModelAndUpdateComponentsStatus();
+        }
+
+        return true;
+    }
+
+    bool AiVoicePresenter::OnPress(UIView& view, const PressEvent& event)
+    {
+        UNUSED(event);
+        std::string viewId = view.GetViewId();
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::OnRelease %s", viewId.c_str());
+        /* ----------------------------- 重置60s取消常亮屏timer ---------------------------- */
+        model->reset_ai_screen60s_timer_time();
+        /* -------------------------------------------------------------------------- */
+        std::unordered_map<std::string, std::pair<int16_t, int16_t>> viewIdMap = {
+            {AIVOICERETURNRESULTTEXT_RETURN_BUTTON_VIEW_ID, {AIVOICE_RETURN_RESULT_TEXT_VIEWID, AIVOICE_STARTCHAT_VIEWID}},                        // 返回一级界面,并清除手表聊天记录
+            {AIVOICERETURNRESULTTEXT_CONTINUECHAT_BUTTON_VIEW_ID, {AIVOICE_RETURN_RESULT_TEXT_VIEWID, AIVOICE_LISTENING_VIEWID}},                  // 返回继续聆听,并清除手表聊天记录
+        };
+        auto it = viewIdMap.find(viewId);
+        if (it != viewIdMap.end())
+        {
+            #if 0
+            if(!model->GetIsClickable())
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "当前还不可点击");
+                return true;
+            }
+            #endif
+            if (it->first == AIVOICERETURNRESULTTEXT_CONTINUECHAT_BUTTON_VIEW_ID) // 点击继续对话按钮要发取消当前对话指令,避免AI回应中途按继续对话按钮没有取消上一次对话问题
+            {
+                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "CancelCurAIChat");
+                AiVoiceModel::GetInstance().CancelCurAIChat();
+                // AiVoiceModel::GetInstance().sendAIIsReady();
+                PlayersModel::GetInstance()->HandPausePhoneMusic(); // 暂停手机音乐
+                PlayersModel::GetInstance()->PlayerPause();         // 暂停手机音乐
+            }
+            ChangeViewAndLogicOperator(it->second.first, it->second.second);
+            return true;
+        }
+        return true;
+    }
+
+    bool AiVoicePresenter::OnRelease(UIView &view, const ReleaseEvent &event)
+    {
+        UNUSED(event);
+        std::string viewId = view.GetViewId();
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::OnRelease %s", viewId.c_str());
+        /* ----------------------------- 重置60s取消常亮屏timer ---------------------------- */
+        model->reset_ai_screen60s_timer_time();
+        /* -------------------------------------------------------------------------- */
+
+        // if ((viewId == AIVOICE_CHAT_BUTTON_VIEW_ID) && model->IsExistOpenAIAPIKeys() == false) // 如果点击的是(对话按钮)且未配置apikey
+        // {
+        //     ChangeViewAndLogicOperator(AIVOICE_STARTCHAT_VIEWID, AIVOICE_NOTSETAPIKEYS); /*开始对话界面->API Keys notset界面*/
+        //     return true;
+        // }
+        if (viewId == AIVOICE_APIKEYS_BUTTON_VIEW_ID) // 如果点击的是API Keys按钮(注:暂时不用)
+        {
+            if (model->IsExistOpenAIAPIKeys() == true)
+            {
+                ChangeViewAndLogicOperator(AIVOICE_STARTCHAT_VIEWID, AIVOICE_SETAPIKEYS); /*开始对话界面->API Keys set界面*/
+            }
+            else
+            {
+                ChangeViewAndLogicOperator(AIVOICE_STARTCHAT_VIEWID, AIVOICE_NOTSETAPIKEYS); /*开始对话界面->API Keys notset界面*/
+            }
+            return true;
+        }
+        else if (viewId == AIVOICE_START_CHAT_BUTTON_VIEW_ID) // 如果点击的是开始对话按钮
+        {
+            PlayersModel::GetInstance()->HandPausePhoneMusic(); // 暂停手机音乐
+            PlayersModel::GetInstance()->PlayerPause();         // 暂停手机音乐
+            /*
+             * 进入对话流程:
+             *   1.当手表4G网络正常+与app连接正常 -> 通过4G调用大模型
+             *   2.只有手表4G网络正常            -> 通过4G调用大模型
+             *   3.只有与APP蓝牙连接正常         -> 通过蓝牙连接APP调用大模型
+             *   4.两者连接都异常               -> 返回错误
+             */
+            bool netWork4GState = model->GetMobileDataIsOpen();
+            bool appBluetoothConnectState = model->GetAPPBluetoothIsConnect();
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "netWork4GState = %d,appBluetoothConnectState = %d", netWork4GState, appBluetoothConnectState);
+
+            if (netWork4GState) // 1.手表4G网络正常
+            {
+                // 通过4G调用大模型
+            }
+            else if (appBluetoothConnectState) // 3.只有与APP蓝牙连接正常
+            {
+                // 通过蓝牙连接APP调用大模型
+                ChangeViewAndLogicOperator(AIVOICE_STARTCHAT_VIEWID, AIVOICE_AIMODE_CONNECTING); // LOADING
+            }
+            else // 4.两者连接都异常
+            {
+                // 返回错误
+                ChangeViewAndLogicOperator(AIVOICE_STARTCHAT_VIEWID, AIVOICE_ALERT_APPBLUETOOTH_AND_4GNETWORK_VIEWID);
+                // ChangeViewAndLogicOperator(AIVOICE_STARTCHAT_VIEWID, AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID);
+            }
+            return true;
+        }
+        else if (viewId == FINISH_SPEAKING_BUTTON_VIEW_ID) // 如果点击的是说话完毕按钮
+        {
+            ChangeViewAndLogicOperator(AIVOICE_LISTENING_VIEWID, AIVOICE_THINKING_VIEWID);
+            return true;
+        }
+
+        std::unordered_map<std::string, std::pair<int16_t, int16_t>> viewIdMap = {
+            {ALERT_APPBLUETOOTH_AND_4GNETWORK_ENSURE_BUTTON_VIEW_ID, {AIVOICE_ALERT_APPBLUETOOTH_AND_4GNETWORK_VIEWID, AIVOICE_STARTCHAT_VIEWID}}, // 返回一级界面
+            {AIMODEL_CONNECT_FAILED_ENSURE_BUTTON_VIEW_ID, {AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID, AIVOICE_STARTCHAT_VIEWID}},                     // 返回一级界面
+            {AIVOICECONNECTTIMEOUT_ENSURE_BUTTON_VIEW_ID, {AIVOICE_CONNECT_TIMEOUT_VIEWID, AIVOICE_STARTCHAT_VIEWID}},                             // 返回一级界面
+            {CANCEL_THINKING_BUTTON_VIEW_ID, {AIVOICE_THINKING_VIEWID, AIVOICE_STARTCHAT_VIEWID}},                                                 // 返回一级界面
+            {AIVOICECONNECTINGVIEW_CANCEL_BUTTON_VIEW_ID, {AIVOICE_AIMODE_CONNECTING, AIVOICE_STARTCHAT_VIEWID}},                                  // 返回一级界面
+            // {AIVOICERETURNRESULTTEXT_RETURN_BUTTON_VIEW_ID, {AIVOICE_RETURN_RESULT_TEXT_VIEWID, AIVOICE_STARTCHAT_VIEWID}},                        // 返回一级界面,并清除手表聊天记录
+            // {AIVOICERETURNRESULTTEXT_CONTINUECHAT_BUTTON_VIEW_ID, {AIVOICE_RETURN_RESULT_TEXT_VIEWID, AIVOICE_LISTENING_VIEWID}},                  // 返回继续聆听,并清除手表聊天记录
+        };
+        auto it = viewIdMap.find(viewId);
+        if (it != viewIdMap.end())
+        {
+            // if (it->first == AIVOICERETURNRESULTTEXT_CONTINUECHAT_BUTTON_VIEW_ID) // 点击继续对话按钮要发取消当前对话指令,避免AI回应中途按继续对话按钮没有取消上一次对话问题
+            // {
+            //     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CancelCurAIChat");
+            //     AiVoiceModel::GetInstance().CancelCurAIChat();
+            //     PlayersModel::GetInstance()->HandPausePhoneMusic(); // 暂停手机音乐
+            //     PlayersModel::GetInstance()->PlayerPause();         // 暂停手机音乐
+            // }
+            ChangeViewAndLogicOperator(it->second.first, it->second.second);
+            return true;
+        }
+        return true;
+    }
+
+    bool AiVoicePresenter::OnDrag(UIView &view, const DragEvent &event)
+    {
+        UNUSED(view);
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::OnDrag");
+        if ((event.GetDeltaX() > X_DRAG_OFFSET) && (event.GetDeltaX() > (DOUBLES * MATH_ABS(event.GetDeltaY())))) // 拖动过程中判断是否是水平滑动
+        {
+            AiVoicePresenter::X_DRAG_FLAG = true;
+        }
+        return true;
+    }
+
+    bool AiVoicePresenter::OnDragEnd(UIView &view, const DragEvent &event)
+    {
+        UNUSED(view);
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::OnDragEnd");
+        UIScrollView *scrollView = dynamic_cast<UIScrollView *>(&view);
+        if (scrollView == nullptr)
+        {
+            return false;
+        }
+
+        model->reset_ai_screen60s_timer_time(); // 重置60s取消常亮屏timer
+
+        if (event.GetDragDirection() == DragEvent::DIRECTION_RIGHT_TO_LEFT) /*左滑*/
+        {
+            DragRightToLetfChangeAIModel();
+        }
+        else if (event.GetDragDirection() == DragEvent::DIRECTION_LEFT_TO_RIGHT && AiVoicePresenter::X_DRAG_FLAG) /*右滑*/
+        {
+            if (scrollView == view_->GetAiVoiceScrollView(AIVOICE_STARTCHAT_VIEWID))
+            {
+                /*AI对话界面右滑退出当前Slice*/
+                // NativeAbility::GetInstance().Back(TransitionType::TRANSITION_BACK_TO_HEXAGONS);
+                DragLeftToRightChangeAIModel();
+            }
+            else if (scrollView == view_->GetAiVoiceScrollView(AIVOICE_ALERT_APPBLUETOOTH_AND_4GNETWORK_VIEWID))
+            {
+                /*APP蓝牙与4G网络都连接异常界面右滑退回到开始对话界面*/
+                ChangeViewAndLogicOperator(AIVOICE_ALERT_APPBLUETOOTH_AND_4GNETWORK_VIEWID, AIVOICE_STARTCHAT_VIEWID);
+            }
+            else if (scrollView == view_->GetAiVoiceScrollView(AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID))
+            {
+                /*模型连接失败弹窗界面右滑退回到开始对话界面*/
+                ChangeViewAndLogicOperator(AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID, AIVOICE_STARTCHAT_VIEWID);
+            }
+            else if (scrollView == view_->GetAiVoiceScrollView(AIVOICE_LISTENING_VIEWID))
+            {
+                /*聆听中界面右滑退回到AI对话界面*/
+                ChangeViewAndLogicOperator(AIVOICE_LISTENING_VIEWID, AIVOICE_STARTCHAT_VIEWID);
+            }
+            else if (scrollView == view_->GetAiVoiceScrollView(AIVOICE_THINKING_VIEWID))
+            {
+                /*思考中界面右滑退到AI对话界面*/
+                ChangeViewAndLogicOperator(AIVOICE_THINKING_VIEWID, AIVOICE_STARTCHAT_VIEWID);
+            }
+            else if (scrollView == view_->GetAiVoiceScrollView(AIVOICE_CONNECT_TIMEOUT_VIEWID))
+            {
+                /*连接超时界面右滑退到AI对话界面*/
+                ChangeViewAndLogicOperator(AIVOICE_CONNECT_TIMEOUT_VIEWID, AIVOICE_STARTCHAT_VIEWID);
+            }
+            else if (scrollView == view_->GetAiVoiceScrollView(AIVOICE_AIMODE_CONNECTING))
+            {
+                /*连接超时界面右滑退到AI对话界面*/
+                ChangeViewAndLogicOperator(AIVOICE_AIMODE_CONNECTING, AIVOICE_STARTCHAT_VIEWID);
+            }
+            AiVoicePresenter::X_DRAG_FLAG = false;
+        }
+        else if (model->GetAiModelTextId() == STR_AIMODES_CHATGPT && event.GetDragDirection() == DragEvent::DIRECTION_BOTTOM_TO_TOP) /*上滑*/
+        {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "DIRECTION_BOTTOM_TO_TOP");
+            if (model->IsExistOpenAIAPIKeys() == true)
+            {
+                ChangeViewAndLogicOperator(AIVOICE_STARTCHAT_VIEWID, AIVOICE_SETAPIKEYS); /*开始对话界面->API Keys set界面*/
+            }
+            else
+            {
+                ChangeViewAndLogicOperator(AIVOICE_STARTCHAT_VIEWID, AIVOICE_NOTSETAPIKEYS); /*开始对话界面->API Keys notset界面*/
+            }
+        }
+        return true;
+    }
+
+    bool AiVoicePresenter::OnKeyAct(UIView &view, const KeyEvent &event) // 增加按键事件
+    {
+        UNUSED(view);
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::OnKeyAct");
+        uint16_t keyID = event.GetKeyId();
+        uint16_t keyState = event.GetState();
+        // 如果是power键,且是亮屏状态,按键释放就返回上一级
+        if (keyID == static_cast<uint16_t>(ZliteKeyCode::ZLITE_KEY_POWER) && keyState == 1 && uapi_get_screen_state() == 0)
+        {
+            NativeAbility::GetInstance().Back(TransitionType::TRANSITION_BACK_TO_HEXAGONS);
+            AiVoiceModel::GetInstance().CancelCurAIChat();
+        }
+        return true;
+    }
+
+    void AiVoicePresenter::OnPickerStoped(UIPicker &picker)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::OnPickerStoped,%d", picker.GetSelected());
+        if(view_->GetAiVoiceScrollView(AIVOICE_STARTCHAT_VIEWID) && view_->GetAiVoiceScrollView(AIVOICE_STARTCHAT_VIEWID)->IsVisible() == true)
+        {
+            model->SetSelectAiModel(picker.GetSelected());
+            view_->ChangeAiModelAndUpdateComponentsStatus();
+        }
+        return;
+    }
+
+    // 计算聊天内容ItemView的高度
+    void AiVoicePresenter::calculateChatContentItemViewHeight(std::string text, bool flag)
+    {
+        const char *Text = text.c_str();
+        UILabel label;
+        label.SetPosition(53, 100);
+        label.Resize(flag ? 280 : 200, 60);
+        label.SetStyle(STYLE_TEXT_FONT, 26);
+        label.SetStyle(STYLE_LINE_HEIGHT, 30);
+        label.SetText(Text);
+        label.SetLineBreakMode(UILabel::LINE_BREAK_WRAP);
+        label.SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label.SetFont(DEFAULT_VECTOR_FONT_FILENAME_EN, 26);
+
+        if (label.GetTextHeight() > preHeight)
+        {
+            preHeight = label.GetTextHeight();
+            isScroll = true;
+        }
+        return;
+    }
+
+    //监听高度是否变化
+    void AiVoicePresenter::Notify()
+    {
+        if ((view_->GetAiVoiceScrollView(AIVOICE_RETURN_RESULT_TEXT_VIEWID) != nullptr) &&
+            (view_->GetAiVoiceScrollView(AIVOICE_RETURN_RESULT_TEXT_VIEWID)->IsVisible()))
+        {
+            if (isScroll)
+            {
+                // 监听,让List实现滚动
+                AivoiceReturnResultTextView::GetInstance()->GetChatContentList()->ScrollBy(-120);
+                isScroll = false;
+            }
+        }
+        return;
+    }
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceView.cpp
new file mode 100644 (file)
index 0000000..92f05db
--- /dev/null
@@ -0,0 +1,946 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-05-07 11:25:58
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2025-03-06 16:07:08
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/AiVoice/src/AiVoiceView.cpp
+ */
+#include "aivoice/include/AiVoicePresenter.h"
+#include "aivoice/include/AiVoiceView.h"
+#include "aivoice/include/AiVoiceModel.h"
+#include "wearable_log.h"
+#include "ui_resource_string.h"
+#include "ConfigModel.h"
+namespace OHOS
+{
+
+    static AiVoiceView *g_pAiVoiceView{nullptr};
+
+    AiVoiceView::AiVoiceView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::AiVoiceView");
+        g_pAiVoiceView = this;
+    }
+
+    AiVoiceView::~AiVoiceView()
+    {
+        ClearAll();
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::~AiVoiceView");
+        g_pAiVoiceView = nullptr;
+    }
+
+    AiVoiceView *AiVoiceView::GetInstance()
+    {
+        return g_pAiVoiceView;
+    }
+
+    void AiVoiceView::ClearAll(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ClearAll");
+        if (viewInitStatus)
+        {
+           
+
+            if (AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID] != nullptr)
+            {
+                AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->RemoveAll();
+
+                delete title;
+                title = nullptr;
+
+                delete aiModelImage;
+                aiModelImage = nullptr;
+
+                delete startChatButton;
+                startChatButton = nullptr;
+
+                delete startChatLabel;
+                startChatLabel = nullptr;
+
+                delete chatButton;
+                chatButton = nullptr;
+
+                delete chatLabel;
+                chatLabel = nullptr;
+
+                delete apiKeysLabel;
+                apiKeysLabel = nullptr;
+
+                delete apiKeysButton;
+                apiKeysButton = nullptr;
+
+                delete aiModelPicker;
+                aiModelPicker = nullptr;
+
+                delete buttonBgImage;
+                buttonBgImage = nullptr;
+
+                delete upImage;
+                upImage = nullptr;
+
+                delete AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID];
+                AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID] = nullptr;
+            }
+
+            if (p_AiVoiceBluetoothFailedStartView != nullptr)
+            {
+                delete p_AiVoiceBluetoothFailedStartView;
+                p_AiVoiceBluetoothFailedStartView = nullptr;
+            }
+
+            if (p_AivoiceMobileDataFailedStartView != nullptr)
+            {
+                delete p_AivoiceMobileDataFailedStartView;
+                p_AivoiceMobileDataFailedStartView = nullptr;
+            }
+
+            if (p_AivoiceConnectTimeoutView != nullptr)
+            {
+                delete p_AivoiceConnectTimeoutView;
+                p_AivoiceConnectTimeoutView = nullptr;
+            }
+
+            if (p_AivoiceListeningView != nullptr)
+            {
+                delete p_AivoiceListeningView;
+                p_AivoiceListeningView = nullptr;
+            }
+
+            if (p_AivoiceThinkingView != nullptr)
+            {
+                delete p_AivoiceThinkingView;
+                p_AivoiceThinkingView = nullptr;
+            }
+
+            if (p_AivoiceReturnResultTextView != nullptr)
+            {
+                delete p_AivoiceReturnResultTextView;
+                p_AivoiceReturnResultTextView = nullptr;
+            }
+
+            if (p_SetApiKeysView != nullptr)
+            {
+                delete p_SetApiKeysView;
+                p_SetApiKeysView = nullptr;
+            }
+
+            if (p_NotSetApiKeysView != nullptr)
+            {
+                delete p_NotSetApiKeysView;
+                p_NotSetApiKeysView = nullptr;
+            }
+
+            if (p_ApiKeysDeleteView != nullptr)
+            {
+                delete p_ApiKeysDeleteView;
+                p_ApiKeysDeleteView = nullptr;
+            }
+
+            if (p_AiVoiceConnectingView != nullptr)
+            {
+                delete p_AiVoiceConnectingView;
+                p_AiVoiceConnectingView = nullptr;
+            }
+        }
+    }
+
+    UILabelExt *AiVoiceView::AiVoiceViewLabelInit(LabelConfig &labelconfig)
+    {
+        UILabelExt *label = new UILabelExt();
+        if (label == nullptr)
+        {
+            return nullptr;
+        }
+        label->SetPosition(labelconfig.left, labelconfig.top, labelconfig.width, labelconfig.height);
+        label->SetStyle(STYLE_TEXT_FONT, labelconfig.fontSize);
+        label->SetStyle(STYLE_LINE_HEIGHT, labelconfig.lineHeigh);
+        //TOOD: 待优化
+        if(labelconfig.textId == STR_DEEPSEEK) {
+            label->SetText("DeepSeek");
+        } else
+            label->SetTextId(labelconfig.textId);
+        label->SetLineBreakMode(labelconfig.lineBreakMode);
+        label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label->SetRollSpeed(23);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, labelconfig.fontSize);
+        return label;
+    }
+
+    UIImageView *AiVoiceView::AiVoiceViewImageView(ImageConfig &imageconfig)
+    {
+        UIImageView *Image = new UIImageView();
+        if (Image == nullptr)
+        {
+            return nullptr;
+        }
+        Image->SetPosition(imageconfig.x, imageconfig.y, imageconfig.w, imageconfig.h);
+        Image->SetSrc(imageconfig.src);
+        return Image;
+    }
+
+    UIButton *AiVoiceView::AiVoiceViewButtonInit(ButtonConfig &buttonconfig)
+    {
+        UIButton *button = new UIButton();
+        if (button == nullptr)
+        {
+            return nullptr;
+        }
+        button->SetPosition(buttonconfig.x, buttonconfig.y, buttonconfig.w, buttonconfig.h);
+        button->SetViewId(buttonconfig.ViewId);
+        button->SetStyle(STYLE_BACKGROUND_COLOR, 0xff4fc34c);
+        button->SetStyle(STYLE_BACKGROUND_OPA, 0x00);
+        button->SetStyleForState(STYLE_BACKGROUND_COLOR, 0x00, UIButton::PRESSED);
+        button->SetOnTouchListener(presenter_);
+
+        return button;
+    }
+
+    bool AiVoiceView::CreateAiVoiceViewLabel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CreateAiVoiceViewLabel");
+        LabelConfig labelConfig = {
+            .left = 83,
+            .top = 50,
+            .width = 300,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = AiVoiceModel::GetInstance().GetAiModelTextId(),
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        title = AiVoiceViewLabelInit(labelConfig);
+        if (title == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "title new fail!");
+            return false;
+        }
+        /* ----------------------------- startChatLabel ----------------------------- */
+        labelConfig = {
+            .left = 133,
+            .top = 348,
+            .width = 200,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_START_CHAT, /*开始对话*/
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        startChatLabel = AiVoiceViewLabelInit(labelConfig);
+        if (startChatLabel == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "startChatLabel new fail!");
+            return false;
+        }
+        startChatLabel->SetVisible(false);
+        /* -------------------------------- ChatLabel ------------------------------- */
+        labelConfig = {
+            .left = 93,
+            .top = 350,
+            .width = 100,
+            .height = 30,
+            .fontSize = 26,
+            .lineHeigh = 30,
+            .textId = STR_CHAT, /*对话*/
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        chatLabel = AiVoiceViewLabelInit(labelConfig);
+        if (chatLabel == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "chatLabel new fail!");
+            return false;
+        }
+        chatLabel->SetVisible(false);
+        /* ------------------------------ apiKeysLabel ------------------------------ */
+        labelConfig = {
+            .left = 273,
+            .top = 350,
+            .width = 100,
+            .height = 30,
+            .fontSize = 26,
+            .lineHeigh = 30,
+            .textId = STR_API_KEYS, /*API Keys标签*/
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        apiKeysLabel = AiVoiceViewLabelInit(labelConfig);
+        if (apiKeysLabel == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "apiKeysLabel new fail!");
+            return false;
+        }
+        apiKeysLabel->SetVisible(false);
+
+        return true;
+    }
+
+    bool AiVoiceView::CreateAiVoiceViewImageView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CreateAiVoiceViewImageView");
+        ImageConfig imagecinfig = {
+            .x = 173,
+            .y = 143,
+            .w = 120,
+            .h = 120,
+            .src = "",
+        };
+
+        // 根据视图ID设置文本ID
+        auto it = TextIdToImagePath.find(AiVoiceModel::GetInstance().GetAiModelTextId());
+        if (it != TextIdToImagePath.end())
+        {
+            imagecinfig.src = it->second;
+        }
+
+        aiModelImage = AiVoiceViewImageView(imagecinfig);
+        if (aiModelImage == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceView::aiModelImage is nullptr!!");
+            return false;
+        }
+        aiModelImage->SetTouchable(true);
+        aiModelImage->SetViewId(AIVOICE_IMGAE_VIEW_ID);
+        aiModelImage->SetOnClickListener(presenter_);
+        /* -------------------------------- buttonBgImage -------------------------------- */
+        imagecinfig = {
+            .x = 208,
+            .y = 340,
+            .w = 48,
+            .h = 56,
+            .src = "/user/res/AIVoice/ai_chart_icon.bin",
+        };
+        buttonBgImage = AiVoiceViewImageView(imagecinfig);
+        if (buttonBgImage == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceView::aiModelImage is nullptr!!");
+            return false;
+        }
+        /* --------------------------------- upImage -------------------------------- */
+        imagecinfig = {
+            .x = 213,
+            .y = static_cast<int16_t>(buttonBgImage->GetY() + buttonBgImage->GetHeight() + 10),
+            .w = 40,
+            .h = 40,
+            .src = "/user/res/Sleep/up.bin",
+        };
+        upImage = AiVoiceViewImageView(imagecinfig);
+        if (upImage == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceView::aiModelImage is nullptr!!");
+            return false;
+        }
+        upImage->SetVisible(false);
+        return true;
+    }
+
+    bool AiVoiceView::CreateAiVoiceViewButton(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CreateAiVoiceViewButton");
+        /* ----------------------------- startChatButton ---------------------------- */
+        ButtonConfig buttonconfig = {
+            .x = 43,
+            .y = 328,
+            .w = 380,
+            .h = 80,
+            .ViewId = AIVOICE_START_CHAT_BUTTON_VIEW_ID,
+        };
+        startChatButton = AiVoiceViewButtonInit(buttonconfig);
+        if (startChatButton == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "startChatButton new fail!");
+            return false;
+        }
+        startChatButton->SetVisible(false);
+        const char *image = "/user/res/AIVoice/ai_chart_icon_bg.bin";
+        startChatButton->SetImageSrc(image, image);
+        /* ------------------------------- chatButton ------------------------------- */
+        buttonconfig = {
+            .x = 43,
+            .y = 328,
+            .w = 380,
+            .h = 80,
+            // .ViewId = AIVOICE_CHAT_BUTTON_VIEW_ID,
+            .ViewId = AIVOICE_START_CHAT_BUTTON_VIEW_ID,
+        };
+        chatButton = AiVoiceViewButtonInit(buttonconfig);
+        if (chatButton == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "chatButton new fail!");
+            return false;
+        }
+        chatButton->SetVisible(false);
+        chatButton->SetImageSrc(image, image);
+        /* ------------------------------ apiKeysButton ----------------------------- */
+        buttonconfig = {
+            .x = 238,
+            .y = 320,
+            .w = 170,
+            .h = 90,
+            .ViewId = AIVOICE_APIKEYS_BUTTON_VIEW_ID,
+        };
+        apiKeysButton = AiVoiceViewButtonInit(buttonconfig);
+        if (apiKeysButton == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "apiKeysButton new fail!");
+            return false;
+        }
+        apiKeysButton->SetStyle(STYLE_BACKGROUND_COLOR, 0xff191919);
+        apiKeysButton->SetVisible(false);
+
+        return true;
+    }
+
+    bool AiVoiceView::CreateAiVoiceViewPicker(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CreateAiVoiceViewPicker");
+        if (aiModelPicker == nullptr)
+        {
+            aiModelPicker = new UIPicker();
+            if (aiModelPicker == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "aiModelPicker new fail!");
+                return false;
+            }
+            aiModelPicker->SetPosition(203, 203, 60, 60);
+            aiModelPicker->SetViewId(AIVOICE_PICKER_VIEW_ID);
+            aiModelPicker->SetStyle(STYLE_BACKGROUND_COLOR, 0xffffffff);
+            aiModelPicker->SetStyle(STYLE_BACKGROUND_OPA, 0x00);
+            aiModelPicker->SetStyle(STYLE_BORDER_RADIUS, 150);
+            aiModelPicker->SetItemHeight(40);
+            aiModelPicker->SetLoopState(true);
+            aiModelPicker->SetRotateFactor(1.0);
+            aiModelPicker->RequestFocus();
+            aiModelPicker->RegisterSelectedListener(presenter_);
+            aiModelPicker->SetTextColor(Color::GetColorFromRGBA(0x00, 0x00, 0x00, 0xff), Color::GetColorFromRGBA(0xff, 0x00, 0x00, 0xff));
+            const char *uiPicker1Data[] = {"0", "1", "2", "3", "4", "5"};
+            aiModelPicker->SetValues(uiPicker1Data, sizeof(uiPicker1Data) / sizeof(uiPicker1Data[0]));
+        }
+
+        return true;
+    }
+
+    bool AiVoiceView::CreateAiVoiceScrollView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CreateAiVoiceScrollView");
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID] = new UIScrollView();
+        if (AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID] == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CreateAiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID] new fail!");
+            return false;
+        }
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->SetPosition(0, 0, 466, 466);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->SetTouchable(true);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->SetDraggable(true);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->SetOnDragListener(presenter_);
+        AddViewToRootContainer(AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]);
+
+        return true;
+    }
+
+    void AiVoiceView::CreateAiVoiceView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CreateAiVoiceView");
+        if (!CreateAiVoiceScrollView() || !CreateAiVoiceViewImageView() || !CreateAiVoiceViewPicker() ||
+            !CreateAiVoiceViewLabel() || !CreateAiVoiceViewButton())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CreateAiVoiceView fail!");
+            return;
+        }
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->Add(title);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->Add(aiModelPicker);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->Add(aiModelImage);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->Add(startChatButton);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->Add(startChatLabel);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->Add(chatButton);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->Add(chatLabel);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->Add(apiKeysButton);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->Add(apiKeysLabel);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->Add(buttonBgImage);
+        AiVoiceScrollView[AIVOICE_STARTCHAT_VIEWID]->Add(upImage);
+    }
+
+    void AiVoiceView::OnStart()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::OnStart");
+       
+
+        if (!viewInitStatus)
+        {
+            CreateAiVoiceView();
+            viewInitStatus = true;
+        }
+
+        SetAiVoiceViewAllComponentsVisibilityStatus();
+
+        RootView::GetInstance()->SetOnKeyActListener(presenter_);
+        return;
+    }
+
+
+
+    /*切换到开始对话Ai界面*/
+    bool AiVoiceView::ChangeAiVoiceStartChatView(int16_t thisView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiVoiceStartChatView");
+        if (AiVoiceScrollView[thisView] == nullptr)
+        {
+            AddViewToRootContainer(AiVoiceScrollView[thisView]);
+        }
+        AiVoiceModel::GetInstance().CancelCurAIChat();
+        return true;
+    }
+
+    /*切换到APP蓝牙或4G网络未连接界面界面*/
+    bool AiVoiceView::ChangeAiVoiceBluetoothFailedStartView(int16_t thisView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiVoiceBluetoothFailedStartView");
+        if (AiVoiceScrollView[thisView] == nullptr)
+        {
+            p_AiVoiceBluetoothFailedStartView = new AiVoiceBluetoothFailedStartView();
+            if (p_AiVoiceBluetoothFailedStartView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            // AiVoiceScrollView[thisView] = p_AiVoiceBluetoothFailedStartView->CreateAiVoiceBluetoothFailedStartView();
+            UIScrollView *scrollview = p_AiVoiceBluetoothFailedStartView->CreateAiVoiceBluetoothFailedStartView();
+            if (scrollview == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            AiVoiceScrollView[thisView] = scrollview;
+            AddViewToRootContainer(AiVoiceScrollView[thisView]);
+        }
+        return true;
+    }
+
+    /*切换到模型连接失败界面*/
+    bool AiVoiceView::ChangeAiVoiceMobileDataFailedStartView(int16_t thisView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiVoiceMobileDataFailedStartView");
+        if (AiVoiceScrollView[thisView] == nullptr)
+        {
+            p_AivoiceMobileDataFailedStartView = new AivoiceMobileDataFailedStartView();
+            if (p_AivoiceMobileDataFailedStartView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            // AiVoiceScrollView[thisView] = p_AivoiceMobileDataFailedStartView->CreateAivoiceMobileDataFailedStartView();
+            UIScrollView *scrollview = p_AivoiceMobileDataFailedStartView->CreateAivoiceMobileDataFailedStartView();
+            if (scrollview == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            AiVoiceScrollView[thisView] = scrollview;
+            AddViewToRootContainer(AiVoiceScrollView[thisView]);
+        }
+        return true;
+    }
+
+    /*切换到连接超时界面*/
+    bool AiVoiceView::ChangeAiVoicConnectTimeoutView(int16_t thisView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiVoicConnectTimeoutView");
+        if (AiVoiceScrollView[thisView] == nullptr)
+        {
+            p_AivoiceConnectTimeoutView = new AivoiceConnectTimeoutView();
+            if (p_AivoiceConnectTimeoutView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            // AiVoiceScrollView[thisView] = p_AivoiceConnectTimeoutView->CreateAivoiceConnectTimeoutView();
+            UIScrollView *scrollview = p_AivoiceConnectTimeoutView->CreateAivoiceConnectTimeoutView();
+            if (scrollview == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            AiVoiceScrollView[thisView] = scrollview;
+            AddViewToRootContainer(AiVoiceScrollView[thisView]);
+        }
+
+        return true;
+    }
+
+    /*切换到聆听中界面*/
+    bool AiVoiceView::ChangeAiVoicListeningView(int16_t thisView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiVoicListeningView");
+        if (AiVoiceScrollView[thisView] == nullptr)
+        {
+            p_AivoiceListeningView = new AivoiceListeningView();
+            if (p_AivoiceListeningView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            // AiVoiceScrollView[thisView] = p_AivoiceListeningView->CreateAivoiceListeningView();
+            UIScrollView *scrollview = p_AivoiceListeningView->CreateAivoiceListeningView();
+            if (scrollview == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            AiVoiceScrollView[thisView] = scrollview;
+            AddViewToRootContainer(AiVoiceScrollView[thisView]);
+        }
+        if (p_AivoiceListeningView)
+        {
+            p_AivoiceListeningView->GetShowtimeoutLabel()->SetText("10");
+            p_AivoiceListeningView->GetShowtimeoutLabel()->Invalidate();
+        }
+        AiVoiceModel::GetInstance().start_listening_timer();
+        return true;
+    }
+
+    /*切换到思考中界面*/
+    bool AiVoiceView::ChangeAiVoicThinkingView(int16_t thisView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiVoicThinkingView");
+        if (AiVoiceScrollView[thisView] == nullptr)
+        {
+            p_AivoiceThinkingView = new AivoiceThinkingView();
+            if (p_AivoiceThinkingView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            // AiVoiceScrollView[thisView] = p_AivoiceThinkingView->CreateAivoiceThinkingView();
+            UIScrollView *scrollview = p_AivoiceThinkingView->CreateAivoiceThinkingView();
+            if (scrollview == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            AiVoiceScrollView[thisView] = scrollview;
+            AddViewToRootContainer(AiVoiceScrollView[thisView]);
+        }
+        return true;
+    }
+
+    /*切换到返回结果文本界面*/
+    bool AiVoiceView::ChangeAiVoicReturnResultTextView(int16_t thisView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiVoicReturnResultTextView");
+        if (AiVoiceScrollView[thisView] == nullptr)
+        {
+            p_AivoiceReturnResultTextView = new AivoiceReturnResultTextView();
+            if (p_AivoiceReturnResultTextView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            // AiVoiceScrollView[thisView] = p_AivoiceReturnResultTextView->CreateAivoiceReturnResultTextView();
+            UIScrollView *scrollview = p_AivoiceReturnResultTextView->CreateAivoiceReturnResultTextView();
+            if (scrollview == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            AiVoiceScrollView[thisView] = scrollview;
+            AddViewToRootContainer(AiVoiceScrollView[thisView]);
+        }
+        return true;
+    }
+
+    /*切换到setapikeys界面*/
+    bool AiVoiceView::ChangeAiVoicSetApiKeysView(int16_t thisView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiVoicSetApiKeysView");
+        if (AiVoiceScrollView[thisView] == nullptr)
+        {
+            p_SetApiKeysView = new SetApiKeysView();
+            if (p_SetApiKeysView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            // AiVoiceScrollView[thisView] = p_SetApiKeysView->CreateSetApiKeysView();
+            UIScrollView *scrollview = p_SetApiKeysView->CreateSetApiKeysView();
+            if (scrollview == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            AiVoiceScrollView[thisView] = scrollview;
+            AddViewToRootContainer(AiVoiceScrollView[thisView]);
+        }
+        return true;
+    }
+
+    /*切换到notsetapikeys界面*/
+    bool AiVoiceView::ChangeAiVoicNotSetApiKeysView(int16_t thisView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiVoicNotSetApiKeysView");
+        if (AiVoiceScrollView[thisView] == nullptr)
+        {
+            p_NotSetApiKeysView = new NotSetApiKeysView();
+            if (p_NotSetApiKeysView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            // AiVoiceScrollView[thisView] = p_NotSetApiKeysView->CreateNotSetApiKeysView();
+            UIScrollView *scrollview = p_NotSetApiKeysView->CreateNotSetApiKeysView();
+            if (scrollview == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            AiVoiceScrollView[thisView] = scrollview;
+            AddViewToRootContainer(AiVoiceScrollView[thisView]);
+        }
+        return true;
+    }
+
+    /*切换到apikeys删除界面*/
+    bool AiVoiceView::ChangeAiVoicApiKeysDeleteView(int16_t thisView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiVoicApiKeysDeleteView");
+        if (AiVoiceScrollView[thisView] == nullptr)
+        {
+            p_ApiKeysDeleteView = new ApiKeysDeleteView();
+            if (p_ApiKeysDeleteView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            // AiVoiceScrollView[thisView] = p_ApiKeysDeleteView->CreateApiKeysDeleteView();
+            UIScrollView *scrollview = p_ApiKeysDeleteView->CreateApiKeysDeleteView();
+            if (scrollview == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            AiVoiceScrollView[thisView] = scrollview;
+            AddViewToRootContainer(AiVoiceScrollView[thisView]);
+        }
+        return true;
+    }
+
+    /*切换到AI正在连接中视图*/
+    bool AiVoiceView::ChangeAiVoicConnectingView(int16_t thisView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiVoicConnectingView");
+        if (AiVoiceScrollView[thisView] == nullptr)
+        {
+            p_AiVoiceConnectingView = new AiVoiceConnectingView();
+            if (p_AiVoiceConnectingView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            // AiVoiceScrollView[thisView] = p_AiVoiceConnectingView->CreateAiVoiceConnectingView();
+            UIScrollView *scrollview = p_AiVoiceConnectingView->CreateAiVoiceConnectingView();
+            if (scrollview == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "new AiVoiceScrollView[%d] fail", thisView);
+                return false;
+            }
+            AiVoiceScrollView[thisView] = scrollview;
+            AddViewToRootContainer(AiVoiceScrollView[thisView]);
+        }
+        return true;
+    }
+
+    struct AiVoiceViewMapper
+    {
+        const int16_t viewId;
+        bool (AiVoiceView::*func)(int16_t thisView);
+    };
+
+    static const AiVoiceViewMapper ViewMapper[] = {
+        {AIVOICE_STARTCHAT_VIEWID, &AiVoiceView::ChangeAiVoiceStartChatView},
+        {AIVOICE_ALERT_APPBLUETOOTH_AND_4GNETWORK_VIEWID, &AiVoiceView::ChangeAiVoiceBluetoothFailedStartView},
+        {AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID, &AiVoiceView::ChangeAiVoiceMobileDataFailedStartView},
+        {AIVOICE_CONNECT_TIMEOUT_VIEWID, &AiVoiceView::ChangeAiVoicConnectTimeoutView},
+        {AIVOICE_LISTENING_VIEWID, &AiVoiceView::ChangeAiVoicListeningView},
+        {AIVOICE_THINKING_VIEWID, &AiVoiceView::ChangeAiVoicThinkingView},
+        {AIVOICE_RETURN_RESULT_TEXT_VIEWID, &AiVoiceView::ChangeAiVoicReturnResultTextView},
+        {AIVOICE_SETAPIKEYS, &AiVoiceView::ChangeAiVoicSetApiKeysView},
+        {AIVOICE_NOTSETAPIKEYS, &AiVoiceView::ChangeAiVoicNotSetApiKeysView},
+        {AIVOICE_APIKEYS_DELETE, &AiVoiceView::ChangeAiVoicApiKeysDeleteView},
+        {AIVOICE_AIMODE_CONNECTING, &AiVoiceView::ChangeAiVoicConnectingView},
+    };
+
+    bool AiVoiceView::ClickFunc(int16_t interface)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ClickFunc");
+        int funcSize = sizeof(ViewMapper) / sizeof(ViewMapper[0]);
+        for (int i = 0; i < funcSize; i++)
+        {
+            if (interface == ViewMapper[i].viewId)
+            {
+                bool jug = (this->*(ViewMapper[i].func))(interface);
+                if (jug == false)
+                {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ClickFunc err.");
+                    return false;
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    bool AiVoiceView::CheckViewParam(int16_t hideView, int16_t showView)
+    {
+        if (showView < 0 || showView >= MAX_AIVOICE_VIEWID)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CheckViewParam showView err.");
+            return false;
+        }
+
+        if (hideView < 0 || hideView >= MAX_AIVOICE_VIEWID)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CheckViewParam hideView err.");
+            return false;
+        }
+
+        return true;
+    }
+
+    static const int16 AiVoiceDestroyMapper[] = {
+        AIVOICE_AIMODE_CONNECTING,
+    };
+
+    void AiVoiceView::DestroyTempView(int16_t hideView)
+    {
+        int viewSize = sizeof(AiVoiceDestroyMapper) / sizeof(AiVoiceDestroyMapper[0]);
+        for (int i = 0; i < viewSize; i++)
+        {
+            if (hideView == AiVoiceDestroyMapper[i])
+            {
+                if (AiVoiceScrollView[hideView] != nullptr)
+                {
+                    GetRootContainer()->Remove(AiVoiceScrollView[hideView]);
+                    AiVoiceScrollView[hideView] = nullptr;
+                }
+                break;
+            }
+        }
+        switch (hideView)
+        {
+        case AIVOICE_AIMODE_CONNECTING:
+            if (p_AiVoiceConnectingView)
+            {
+                delete p_AiVoiceConnectingView;
+                p_AiVoiceConnectingView = nullptr;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+    void AiVoiceView::ChangeView(int16_t hideView, int16_t showView)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeView");
+        if (!CheckViewParam(hideView, showView))
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CheckViewParam failed.");
+            return;
+        }
+        AiVoiceScrollView[hideView]->SetVisible(false);
+        ClickFunc(showView);
+        AiVoiceScrollView[showView]->SetVisible(true);
+        if (AiVoiceScrollView[showView] != nullptr)
+        {
+            AiVoiceScrollView[showView]->SetVisible(true);
+        }
+        else
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceScrollView[%d] is nullptr", showView);
+        }
+        Draw();
+        DestroyTempView(hideView);
+        AiVoiceModel::GetInstance().SetCurView(showView);
+        return;
+    }
+
+    UIScrollView *AiVoiceView::GetAiVoiceScrollView(int16_t index)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::GetAiVoiceScrollView");
+        if (index >= 0 && index < MAX_AIVOICE_VIEWID)
+        {
+            return AiVoiceScrollView[index];
+        }
+        else
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Overstep ones bounds");
+            return nullptr;
+        }
+    }
+
+    void AiVoiceView::SetAiVoiceViewAllComponentsVisibilityStatus(void)
+    {
+        bool isAiModeChatGpt = (AiVoiceModel::GetInstance().GetAiModelTextId() == STR_AIMODES_CHATGPT);
+
+        SetComponentVisibility(chatButton, isAiModeChatGpt);
+        // SetComponentVisibility(chatLabel, isAiModeChatGpt);
+        // SetComponentVisibility(apiKeysButton, isAiModeChatGpt);
+        // SetComponentVisibility(apiKeysLabel, isAiModeChatGpt);
+        // SetComponentVisibility(upImage, isAiModeChatGpt);
+
+        // SetComponentVisibility(startChatLabel, !isAiModeChatGpt);
+        SetComponentVisibility(startChatButton, !isAiModeChatGpt);
+    }
+
+    void AiVoiceView::SetComponentVisibility(UIView *component, bool isVisible)
+    {
+        if (component)
+        {
+            component->SetVisible(isVisible);
+        }
+    }
+
+    void AiVoiceView::ChangeAiModelAndUpdateComponentsStatus(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::ChangeAiModelAndUpdateComponentsStatus");
+        int textId = AiVoiceModel::GetInstance().GetAiModelTextId();
+        if (title)
+        {
+            if(textId == STR_DEEPSEEK) 
+            {
+                title->SetText("DeepSeek");
+            } 
+            else 
+            {
+            title->SetTextId(textId);
+            title->ForceResetText();
+            }
+        }
+        if (aiModelImage)
+        {
+            auto it = TextIdToImagePath.find(textId);
+            if (it != TextIdToImagePath.end())
+            {
+                aiModelImage->SetSrc(it->second);
+                aiModelImage->Invalidate();
+            }
+        }
+
+        SetAiVoiceViewAllComponentsVisibilityStatus();
+
+        /*更新title的textid*/
+        if (p_AiVoiceBluetoothFailedStartView)
+        {
+            p_AiVoiceBluetoothFailedStartView->UpdateTitleTextId(textId);
+        }
+        if (p_AivoiceReturnResultTextView)
+        {
+            p_AivoiceReturnResultTextView->UpdateTitleTextId(textId);
+        }
+        if (p_AivoiceMobileDataFailedStartView)
+        {
+            p_AivoiceMobileDataFailedStartView->UpdateTitleTextId(textId);
+        }
+        if (p_AivoiceConnectTimeoutView)
+        {
+            p_AivoiceConnectTimeoutView->UpdateTitleTextId(textId);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceChatContentListAdapter.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceChatContentListAdapter.cpp
new file mode 100644 (file)
index 0000000..19e8f74
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-03-28 14:27:05
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-10-19 17:16:50
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/language/src/AivoiceChatContentListAdapter.cpp
+ */
+#include "aivoice/include/AivoiceChatContentListAdapter.h"
+#include "wearable_log.h"
+#include <UiConfig.h>
+
+namespace OHOS
+{
+
+    AivoiceChatContentListAdapter::AivoiceChatContentListAdapter()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceChatContentListAdapter::AivoiceChatContentListAdapter");
+    }
+
+    AivoiceChatContentListAdapter::~AivoiceChatContentListAdapter()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceChatContentListAdapter::~AivoiceChatContentListAdapter");
+        listData.clear();
+    }
+
+    uint16_t AivoiceChatContentListAdapter::GetCount(void)
+    {
+        return listData.size();
+    }
+
+    std::list<ChatContentItem> &AivoiceChatContentListAdapter::GetChatContentItem()
+    {
+        return listData;
+    }
+
+    void AivoiceChatContentListAdapter::SetData(std::list<ChatContentItem> &data)
+    {
+        if (!listData.empty())
+        {
+            listData.clear();
+        }
+        std::list<ChatContentItem>::iterator it;
+        for (it = data.begin(); it != data.end(); it++)
+        {
+            listData.push_back(*it);
+        }
+    }
+
+    void AivoiceChatContentListAdapter::ClearData(void)
+    {
+        if (!listData.empty())
+        {
+            listData.clear();
+        }
+    }
+
+    void AivoiceChatContentListAdapter::calculateChatContentItemViewHeight(std::string text, bool flag)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceChatContentListAdapter::calculateChatContentItemViewHeight");
+
+        const char *Text = text.c_str();
+        aiAnswerFlag = flag;
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Text = %s,aiAnswerFlag = %d\n", Text, aiAnswerFlag);
+
+        UILabel label;
+        label.SetPosition(53, 100);
+        label.Resize(aiAnswerFlag ? 280 : 200, 60);
+        label.SetStyle(STYLE_TEXT_FONT, 26);
+        label.SetStyle(STYLE_LINE_HEIGHT, 30);
+        label.SetText(Text);
+        label.SetLineBreakMode(UILabel::LINE_BREAK_WRAP);
+        label.SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label.SetFont(DEFAULT_VECTOR_FONT_FILENAME_EN, 26);
+
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "label.GetHeight = %d,label.GetTextHeight = %d\n", label.GetHeight(), label.GetTextHeight());
+        itemViewHeight = label.GetTextHeight();
+    }
+
+    UIView *AivoiceChatContentListAdapter::GetView(UIView *inView, int16_t index)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceChatContentListAdapter::GetView,index %d", index);
+        // 1.先检查列表数据是否为空,若为空则返回空指针
+        if (listData.empty())
+        {
+            return nullptr;
+        }
+        // 2.接着检查索引是否小于0,若小于0则返回空指针
+        if (index < 0)
+        {
+            return nullptr;
+        }
+        // 3.检查是否超出列表数据大小,若超出则返回空指针
+        size_t uindex = index;
+        if (uindex >= listData.size())
+        {
+            return nullptr;
+        }
+        // 4.通过迭代器访问列表中指定索引位置的元素,将其赋值给itemData变量
+        std::list<ChatContentItem>::iterator it = listData.begin();
+        for (int i = 0; i < index; i++)
+        {
+            it++;
+        }
+        ChatContentItem itemData = *it;
+        AivoiceChatContentListItemView *item = nullptr;
+        /* -------------------------------------------------------------------------- */
+        calculateChatContentItemViewHeight(itemData.text, itemData.isAiAnswer);
+        /* -------------------------------------------------------------------------- */
+        // 5.根据传入的inView参数是否已经存在一个视图对象,若为空则创建一个新的LanguageSwitchListItemView对象,否则将inView转换成LanguageSwitchListItemView类型的指针
+        if (inView == nullptr)
+        {
+            item = new AivoiceChatContentListItemView(itemViewHeight, aiAnswerFlag);
+        }
+        else
+        {
+            item = dynamic_cast<AivoiceChatContentListItemView *>(inView);
+            item->ResetItemView(itemViewHeight, aiAnswerFlag);
+        }
+        item->SetViewIndex(index);
+        item->SetItemInfo(itemData);
+        return item;
+    }
+
+    void AivoiceChatContentListAdapter::SetItemClickListener(UIView::OnClickListener *itemclicklistener)
+    {
+        itemClickListener = itemclicklistener;
+    }
+
+    void AivoiceChatContentListAdapter::AddListItem(const ChatContentItem &item)
+    {
+        listData.push_back(item);
+    }
+
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceChatContentListItemView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceChatContentListItemView.cpp
new file mode 100644 (file)
index 0000000..a5b9590
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-06-29 17:27:25
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2025-03-19 10:12:45
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/src/AivoiceChatContentListItemView.cpp
+ */
+
+#include "aivoice/include/AivoiceChatContentListItemView.h"
+#include "aivoice/include/AiVoiceModel.h"
+#include "wearable_log.h"
+
+namespace OHOS
+{
+
+    static constexpr const int16_t ITEM_VIEW_X = 0;   /*itemview x坐标*/
+    static constexpr const int16_t ITEM_VIEW_Y = 0;   /*itemview y坐标*/
+    static constexpr const int16_t ITEM_VIEW_W = 360; /*itemview 宽*/
+    static constexpr const int16_t ITEM_VIEW_H = 80;  /*itemview 高*/
+
+    static constexpr const int16_t CHATCONTENTLABEL_X = 40;
+    static constexpr const int16_t CHATCONTENTLABEL_Y = 25;
+    static constexpr const int16_t CHATCONTENTLABEL_TEXT_FONT = 26;
+    static constexpr const int16_t CHATCONTENTLABEL_LINE_HEIGHT = 30;
+
+    static constexpr const int64_t RADIUS = 20;
+
+    static constexpr const int16_t QUESTION_CHATCONTENTIMAGE_X = 0;
+    static constexpr const int16_t ANSWER_CHATCONTENTIMAGE_X = 289;
+
+    static constexpr const int16_t QUESTION_CHATCONTENTSCROLLVIEW_X = 20;
+    static constexpr const int16_t ANSWER_CHATCONTENTSCROLLVIEW_X = 59;
+
+    static constexpr const int16_t QUESTION_CHATCONTENTSCROLLVIEW_W = 340;
+    static constexpr const int16_t ANSWER_CHATCONTENTSCROLLVIEW_W = 280;
+
+    static constexpr const int16_t QUESTION_CHATCONTENTLABEL_W = 280;
+    static constexpr const int16_t ANSWER_CHATCONTENTLABEL_W = 200;
+
+    static constexpr const char *QUESTION_ITEM_IMAGE_SRC = "/user/res/AIVoice/AI_RecGreen.bin";
+    static constexpr const char *ANSWER_ITEM_IMAGE_SRC = "/user/res/AIVoice/AI_RecBlack.bin";
+
+    static constexpr const int64_t QUESTION_ITEM_VIEW_COLOR = 0xff4fc34c; /*0xff4fc34c*/
+    static constexpr const int64_t ANSWER_ITEM_VIEW_COLOR = 0xff191919;   /*0xff191919*/
+
+    AivoiceChatContentListItemView::AivoiceChatContentListItemView(int viewHeight, bool isAiAnswerFlag)
+        : m_viewHeight(viewHeight), m_isAiAnswerFalg(isAiAnswerFlag)
+    {
+        SetPosition(ITEM_VIEW_X, ITEM_VIEW_Y);
+        Resize(ITEM_VIEW_W, m_viewHeight + ITEM_VIEW_H);
+        SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
+        SetStyle(STYLE_BACKGROUND_OPA, 0xff);
+        SetTouchable(true);
+        SetUpChild();
+        Add(&chatContentImage);
+        chatContentScrollView.Add(&chatContentLabel);
+        Add(&chatContentScrollView);
+    }
+
+    AivoiceChatContentListItemView::~AivoiceChatContentListItemView()
+    {
+        Remove(&chatContentImage);
+        chatContentScrollView.Remove(&chatContentLabel);
+        Remove(&chatContentScrollView);
+    }
+
+    void AivoiceChatContentListItemView::SetItemInfo(const ChatContentItem &itemInfo)
+    {
+        chatContentLabel.SetText(itemInfo.text.c_str());
+    }
+
+    void AivoiceChatContentListItemView::ResetItemView(int viewHeight, bool isAiAnswerFlag)
+    {
+        if (viewHeight < 120 * CHATCONTENTLABEL_LINE_HEIGHT + 30) // itemView最高为120 * label行高
+            Resize(ITEM_VIEW_W, viewHeight + ITEM_VIEW_H);
+
+        chatContentImage.SetPosition(isAiAnswerFlag ? QUESTION_CHATCONTENTIMAGE_X : ANSWER_CHATCONTENTIMAGE_X, 0, 70, 30);
+        chatContentImage.SetSrc(isAiAnswerFlag ? ANSWER_ITEM_IMAGE_SRC : QUESTION_ITEM_IMAGE_SRC);
+
+        chatContentScrollView.SetPosition(isAiAnswerFlag ? QUESTION_CHATCONTENTSCROLLVIEW_X : ANSWER_CHATCONTENTSCROLLVIEW_X, 0);
+        if (viewHeight < 120 * CHATCONTENTLABEL_LINE_HEIGHT + 30) // scrollviewView最高为120 * label行高
+            chatContentScrollView.Resize(isAiAnswerFlag ? QUESTION_CHATCONTENTSCROLLVIEW_W : ANSWER_CHATCONTENTSCROLLVIEW_W, GetHeight() - 30);
+        chatContentScrollView.SetStyle(STYLE_BACKGROUND_COLOR, isAiAnswerFlag ? ANSWER_ITEM_VIEW_COLOR : QUESTION_ITEM_VIEW_COLOR);
+
+        if (viewHeight < 120 * CHATCONTENTLABEL_LINE_HEIGHT) // label最高为120 * label行高
+        {
+            chatContentLabel.Resize(isAiAnswerFlag ? QUESTION_CHATCONTENTLABEL_W : ANSWER_CHATCONTENTLABEL_W, viewHeight);
+        }
+        else
+        {
+            if(!AiVoiceModel::GetInstance().GetIsLimitDisplayed())
+            {
+                AiVoiceModel::GetInstance().SetIsLimitDisplayed(true);
+                chatContentLabel.SetLineBreakMode(isAiAnswerFlag ? UILabel::LINE_BREAK_ELLIPSIS : UILabel::LINE_BREAK_WRAP);//超过高度在末尾用省略号替换
+            }
+        }
+    }
+
+    void AivoiceChatContentListItemView::SetUpChild()
+    {
+        chatContentImage.SetPosition(m_isAiAnswerFalg ? QUESTION_CHATCONTENTIMAGE_X : ANSWER_CHATCONTENTIMAGE_X, 0, 70, 30);
+        chatContentImage.SetSrc(m_isAiAnswerFalg ? ANSWER_ITEM_IMAGE_SRC : QUESTION_ITEM_IMAGE_SRC);
+
+        chatContentScrollView.SetPosition(m_isAiAnswerFalg ? QUESTION_CHATCONTENTSCROLLVIEW_X : ANSWER_CHATCONTENTSCROLLVIEW_X, 0);
+        chatContentScrollView.Resize(m_isAiAnswerFalg ? QUESTION_CHATCONTENTSCROLLVIEW_W : ANSWER_CHATCONTENTSCROLLVIEW_W, GetHeight() - 30);
+        chatContentScrollView.SetStyle(STYLE_BACKGROUND_COLOR, m_isAiAnswerFalg ? ANSWER_ITEM_VIEW_COLOR : QUESTION_ITEM_VIEW_COLOR);
+        chatContentScrollView.SetStyle(STYLE_BACKGROUND_OPA, 0xff);
+        chatContentScrollView.SetStyle(STYLE_BORDER_RADIUS, RADIUS);
+        chatContentScrollView.SetTouchable(false);
+
+        chatContentLabel.SetPosition(CHATCONTENTLABEL_X, CHATCONTENTLABEL_Y);
+        chatContentLabel.Resize(m_isAiAnswerFalg ? QUESTION_CHATCONTENTLABEL_W : ANSWER_CHATCONTENTLABEL_W, m_viewHeight);
+        chatContentLabel.SetStyle(STYLE_TEXT_FONT, CHATCONTENTLABEL_TEXT_FONT);
+        chatContentLabel.SetStyle(STYLE_LINE_HEIGHT, CHATCONTENTLABEL_LINE_HEIGHT);
+        chatContentLabel.SetLineBreakMode(UILabel::LINE_BREAK_WRAP);
+        chatContentLabel.SetAlign(TEXT_ALIGNMENT_LEFT, TEXT_ALIGNMENT_CENTER);
+        chatContentLabel.SetFont(DEFAULT_VECTOR_FONT_FILENAME_EN, CHATCONTENTLABEL_TEXT_FONT);
+    }
+
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceConnectTimeoutView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceConnectTimeoutView.cpp
new file mode 100644 (file)
index 0000000..babb779
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-05-07 11:25:58
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-11-14 17:29:47
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/AiVoice/src/AivoiceConnectTimeoutView.cpp
+ */
+#include "aivoice/include/AiVoicePresenter.h"
+#include "aivoice/include/AivoiceConnectTimeoutView.h"
+#include "aivoice/include/AiVoiceModel.h"
+#include "wearable_log.h"
+#include "ui_resource_string.h"
+#include <UiConfig.h>
+namespace OHOS
+{
+    static constexpr const int16_t LABEL_ROLL_SPEED = 70;
+
+    static AivoiceConnectTimeoutView *g_pAivoiceConnectTimeoutView{nullptr};
+
+    AivoiceConnectTimeoutView::AivoiceConnectTimeoutView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::AivoiceConnectTimeoutView");
+        g_pAivoiceConnectTimeoutView = this;
+    }
+
+    AivoiceConnectTimeoutView::~AivoiceConnectTimeoutView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::~AivoiceConnectTimeoutView");
+        ClearAll();
+        g_pAivoiceConnectTimeoutView = nullptr;
+    }
+
+    AivoiceConnectTimeoutView *AivoiceConnectTimeoutView::GetInstance()
+    {
+        return g_pAivoiceConnectTimeoutView;
+    }
+
+    void AivoiceConnectTimeoutView::ClearAll(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::ClearAll");
+        if (scrollView != nullptr)
+        {
+            scrollView->RemoveAll();
+            if (title != nullptr)
+            {
+                delete title;
+                title = nullptr;
+            }
+            if (attentionImage != nullptr)
+            {
+                delete attentionImage;
+                attentionImage = nullptr;
+            }
+            if (NoteLabel != nullptr)
+            {
+                delete NoteLabel;
+                NoteLabel = nullptr;
+            }
+            if (ensure != nullptr)
+            {
+                delete ensure;
+                ensure = nullptr;
+            }
+            if (ensureButton != nullptr)
+            {
+                delete ensureButton;
+                ensureButton = nullptr;
+            }
+            delete scrollView;
+            scrollView = nullptr;
+        }
+    }
+
+    UILabelExt *AivoiceConnectTimeoutView::AivoiceConnectTimeoutLabelInit(LabelConfig &labelconfig)
+    {
+        UILabelExt *label = new UILabelExt();
+        if (label == nullptr)
+        {
+            return nullptr;
+        }
+        label->SetPosition(labelconfig.left, labelconfig.top, labelconfig.width, labelconfig.height);
+        label->SetStyle(STYLE_TEXT_FONT, labelconfig.fontSize);
+        label->SetStyle(STYLE_LINE_HEIGHT, labelconfig.lineHeigh);
+        //TOOD: 待优化
+        if(labelconfig.textId == STR_DEEPSEEK) {
+            label->SetText("DeepSeek");
+        } else
+            label->SetTextId(labelconfig.textId);
+        label->SetLineBreakMode(labelconfig.lineBreakMode);
+        label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, labelconfig.fontSize);
+        label->SetRollSpeed(LABEL_ROLL_SPEED);
+        return label;
+    }
+
+    UIButton *AivoiceConnectTimeoutView::AivoiceConnectTimeoutButtonInit(ButtonConfig &buttonconfig)
+    {
+        UIButton *button = new UIButton();
+        if (button == nullptr)
+        {
+            return nullptr;
+        }
+        button->SetPosition(buttonconfig.x, buttonconfig.y, buttonconfig.w, buttonconfig.h);
+        button->SetViewId(buttonconfig.ViewId);
+        button->SetStyle(STYLE_BACKGROUND_COLOR, 0xff191919);
+        button->SetStyle(STYLE_BACKGROUND_OPA, 0xff);
+        button->SetStyleForState(STYLE_BACKGROUND_COLOR, 0xff383838, UIButton::PRESSED);
+
+        return button;
+    }
+
+    UIImageView *AivoiceConnectTimeoutView::AivoiceConnectTimeoutImageInit(ImageConfig &imageconfig)
+    {
+        UIImageView *Image = new UIImageView();
+        if (Image == nullptr)
+        {
+            return nullptr;
+        }
+        Image->SetPosition(imageconfig.x, imageconfig.y, imageconfig.w, imageconfig.h);
+        return Image;
+    }
+
+    bool AivoiceConnectTimeoutView::CreateAivoiceConnectTimeoutScrollView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::CreateAivoiceConnectTimeoutScrollView");
+        scrollView = new UIScrollView();
+        if (scrollView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::scrollView new fail!");
+            return false;
+        }
+        UIView::OnDragListener *dragListener = static_cast<UIView::OnDragListener *>(AiVoicePresenter::GetInstance());
+        if (dragListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::dragListener new fail!");
+            return false;
+        }
+        scrollView->SetOnDragListener(dragListener);
+        scrollView->SetPosition(0, 0, 466, 466);
+        scrollView->SetTouchable(true);
+        scrollView->SetDraggable(true);
+
+        return true;
+    }
+
+    bool AivoiceConnectTimeoutView::CreateAivoiceConnectTimeoutLabel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::CreateAivoiceConnectTimeoutLabel");
+        LabelConfig labelconfig = {
+            .left = 83,
+            .top = 50,
+            .width = 300,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = AiVoiceModel::GetInstance().GetAiModelTextId(),
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        title = AivoiceConnectTimeoutLabelInit(labelconfig);
+        if (title == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::title is nullptr!");
+            return false;
+        }
+        /* -------------------------------------------------------------------------- */
+        NoteLabel = new UILabelExt();
+        if (NoteLabel == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "NoteLabel is nullptr!");
+            return false;
+        }
+        NoteLabel->SetPosition(53, 222, 360, 70);
+        NoteLabel->SetStyle(STYLE_TEXT_FONT, 30);
+        NoteLabel->SetStyle(STYLE_LINE_HEIGHT, 35);
+        NoteLabel->SetLineBreakMode(UILabel::LINE_BREAK_OSCILLATION);
+        NoteLabel->SetRollSpeed(23);
+        NoteLabel->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        NoteLabel->SetFont(DEFAULT_VECTOR_FONT_FILENAME_EN, 30);
+        /* -------------------------------------------------------------------------- */
+        labelconfig = {
+            .left = 133,
+            .top = 368,
+            .width = 200,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_OK,
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        ensure = AivoiceConnectTimeoutLabelInit(labelconfig);
+        if (ensure == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::ensure is nullptr!");
+            return false;
+        }
+
+        return true;
+    }
+
+    bool AivoiceConnectTimeoutView::CreateAivoiceConnectTimeoutButton(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::CreateAivoiceConnectTimeoutButton");
+        ButtonConfig buttonconfig = {
+            .x = 93,
+            .y = 340,
+            .w = 280,
+            .h = 90,
+            .ViewId = AIVOICECONNECTTIMEOUT_ENSURE_BUTTON_VIEW_ID,
+        };
+        ensureButton = AivoiceConnectTimeoutButtonInit(buttonconfig);
+        if (ensureButton == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ensureButton new fail!");
+            return false;
+        }
+        UIView::OnTouchListener *touchListener = static_cast<UIView::OnTouchListener *>(AiVoicePresenter::GetInstance());
+        if (touchListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::touchListener can not be nullptr!");
+            return false;
+        }
+        ensureButton->SetOnTouchListener(touchListener);
+
+        return true;
+    }
+
+    bool AivoiceConnectTimeoutView::CreateAivoiceConnectTimeoutImage(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::CreateAivoiceConnectTimeoutImage");
+        ImageConfig imageconfig = {
+            .x = 193,
+            .y = 120,
+            .w = 80,
+            .h = 80,
+        };
+        attentionImage = AivoiceConnectTimeoutImageInit(imageconfig);
+        if (attentionImage == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "attentionImage new fail!");
+            return false;
+        }
+        attentionImage->SetStyle(STYLE_BORDER_RADIUS, 100);
+        attentionImage->SetSrc(PNG_ATTENTION_IMAGE);
+
+        return true;
+    }
+
+    UIScrollView *AivoiceConnectTimeoutView::CreateAivoiceConnectTimeoutView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::CreateAivoiceConnectTimeoutView");
+        if (scrollView == nullptr)
+        {
+            if (!CreateAivoiceConnectTimeoutScrollView() || !CreateAivoiceConnectTimeoutLabel() ||
+                !CreateAivoiceConnectTimeoutButton() || !CreateAivoiceConnectTimeoutImage())
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceConnectTimeoutView::CreateAivoiceConnectTimeoutView fail!!");
+                return nullptr;
+            }
+            scrollView->Add(title);
+            scrollView->Add(attentionImage);
+            scrollView->Add(NoteLabel);
+            scrollView->Add(ensureButton);
+            scrollView->Add(ensure);
+        }
+        return scrollView;
+    }
+
+    void AivoiceConnectTimeoutView::UpdateTitleTextId(int textId)
+    {
+        if (title)
+        {
+            if(textId == STR_DEEPSEEK) 
+            {
+                title->SetText("DeepSeek");
+            } 
+            else 
+            {
+            title->SetTextId(textId);
+            title->ForceResetText();
+            }
+        }
+    }
+
+    // 更新错误信息内容
+    void AivoiceConnectTimeoutView::UpdateNoteText()
+    {
+        if (NoteLabel)
+        {
+            // NoteLabel->SetText("");
+            std::string text = AiVoiceModel::GetInstance().GetErrnote();
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "text = %s", text.c_str());
+            NoteLabel->SetText(text.c_str());
+            NoteLabel->SetLineBreakMode(UILabel::LINE_BREAK_OSCILLATION);
+            NoteLabel->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+            NoteLabel->Invalidate();
+        }
+    }
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceListeningView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceListeningView.cpp
new file mode 100644 (file)
index 0000000..050d452
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-05-07 11:25:58
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-11-05 11:09:40
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/AiVoice/src/AivoiceListeningView.cpp
+ */
+#include "aivoice/include/AiVoicePresenter.h"
+#include "aivoice/include/AivoiceListeningView.h"
+#include "wearable_log.h"
+#include "ui_resource_string.h"
+#include <UiConfig.h>
+#include "uicomponents/UIComponents.h"
+// #include "common/image_cache_manager.h"
+namespace OHOS
+{
+
+    static AivoiceListeningView *g_pAivoiceListeningView{nullptr};
+
+    AivoiceListeningView::AivoiceListeningView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::AivoiceListeningView");
+        g_pAivoiceListeningView = this;
+    }
+
+    AivoiceListeningView::~AivoiceListeningView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::~AivoiceListeningView");
+        ClearAll();
+        g_pAivoiceListeningView = nullptr;
+    }
+
+    AivoiceListeningView *AivoiceListeningView::GetInstance()
+    {
+        return g_pAivoiceListeningView;
+    }
+
+    void AivoiceListeningView::ClearAll(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::ClearAll");
+        if (scrollView != nullptr)
+        {
+            scrollView->RemoveAll();
+
+            if (title != nullptr)
+            {
+                delete title;
+                title = nullptr;
+            }
+
+            if (AiVoiceListeningImageAnimatorView != nullptr)
+            {
+                AiVoiceListeningImageAnimatorView->Stop();
+                delete AiVoiceListeningImageAnimatorView;
+                AiVoiceListeningImageAnimatorView = nullptr;
+
+                FreeImageInfoArray(AiVoiceListeningPathsArray, AIVoiceListeningImagePaths, AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES);
+            }
+
+            if (showtimeout != nullptr)
+            {
+                delete showtimeout;
+                showtimeout = nullptr;
+            }
+
+            if (finishSpeak != nullptr)
+            {
+                delete finishSpeak;
+                finishSpeak = nullptr;
+            }
+
+            if (finishSpeakButton != nullptr)
+            {
+                delete finishSpeakButton;
+                finishSpeakButton = nullptr;
+            }
+
+            delete scrollView;
+            scrollView = nullptr;
+        }
+    }
+
+    UILabelExt *AivoiceListeningView::AivoiceListeningLabelInit(LabelConfig &labelconfig)
+    {
+        UILabelExt *label = new UILabelExt();
+        if (label == nullptr)
+        {
+            return nullptr;
+        }
+        label->SetPosition(labelconfig.left, labelconfig.top, labelconfig.width, labelconfig.height);
+        label->SetStyle(STYLE_TEXT_FONT, labelconfig.fontSize);
+        label->SetStyle(STYLE_LINE_HEIGHT, labelconfig.lineHeigh);
+        label->SetTextId(labelconfig.textId);
+        label->SetLineBreakMode(labelconfig.lineBreakMode);
+        label->SetRollSpeed(23);
+        label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, labelconfig.fontSize);
+        return label;
+    }
+
+    UIButton *AivoiceListeningView::AivoiceListeningButtonInit(ButtonConfig &buttonconfig)
+    {
+        UIButton *button = new UIButton();
+        if (button == nullptr)
+        {
+            return nullptr;
+        }
+        button->SetPosition(buttonconfig.x, buttonconfig.y, buttonconfig.w, buttonconfig.h);
+        button->SetViewId(buttonconfig.ViewId);
+        button->SetStyle(STYLE_BACKGROUND_COLOR, 0xff191919);
+        button->SetStyle(STYLE_BACKGROUND_OPA, 0xff);
+        button->SetStyleForState(STYLE_BACKGROUND_COLOR, 0xff383838, UIButton::PRESSED);
+
+        return button;
+    }
+
+    UIImageAnimatorView *AivoiceListeningView::AivoiceListeningImageAnimatorInit(ImageAnimatorConfig &imageanimatorconfig)
+    {
+        UIImageAnimatorView *animatorView = new UIImageAnimatorView();
+        if (animatorView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceListeningImageAnimatorView::AiVoiceListeningImageAnimatorView new fail");
+            return nullptr;
+        }
+
+        for (uint8_t i = 0; i < imageanimatorconfig.numFrames; i++)
+        {
+            imageanimatorconfig.imageInfoArray[i].imageInfo = imageanimatorconfig.pathsArray[i];
+            // imageanimatorconfig.imageInfoArray[i].imagePath = (imageanimatorconfig.pathsArray[i]);
+            // imageanimatorconfig.imageInfoArray[i].imageType = IMG_SRC_FILE_PATH;
+            imageanimatorconfig.imageInfoArray[i].imageType = IMG_SRC_IMAGE_INFO;
+            imageanimatorconfig.imageInfoArray[i].pos.x = imageanimatorconfig.x;
+            imageanimatorconfig.imageInfoArray[i].pos.y = imageanimatorconfig.y;
+            imageanimatorconfig.imageInfoArray[i].width = imageanimatorconfig.width;
+            imageanimatorconfig.imageInfoArray[i].height = imageanimatorconfig.height;
+        }
+
+        animatorView->SetPosition(imageanimatorconfig.x, imageanimatorconfig.y, imageanimatorconfig.width, imageanimatorconfig.height);
+        animatorView->SetImageAnimatorSrc(imageanimatorconfig.imageInfoArray, imageanimatorconfig.numFrames, imageanimatorconfig.delay);
+        animatorView->SetRepeat(true);
+        animatorView->SetSizeFixed(true);
+        // animatorView->SetAutoEnable(false);
+        // animatorView->SetResizeMode(UIImageAnimatorView::FILL);
+        animatorView->Start();
+
+        return animatorView;
+    }
+
+    bool AivoiceListeningView::CreateAivoiceListeningScrollView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningScrollView");
+        scrollView = new UIScrollView();
+        if (scrollView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::scrollView new fail!");
+            return false;
+        }
+        scrollView->SetPosition(0, 0, 466, 466);
+        UIView::OnDragListener *dragListener = static_cast<UIView::OnDragListener *>(AiVoicePresenter::GetInstance());
+        if (dragListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::dragListener new fail!");
+            return false;
+        }
+        scrollView->SetOnDragListener(dragListener);
+        scrollView->SetTouchable(true);
+        scrollView->SetDraggable(true);
+
+        return true;
+    }
+
+    bool AivoiceListeningView::CreateAivoiceListeningLabel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningLabel");
+        LabelConfig labelconfig = {
+            .left = 83,
+            .top = 50,
+            .width = 300,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_LISTENING,
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        title = AivoiceListeningLabelInit(labelconfig);
+        if (title == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::title is nullptr!");
+            return false;
+        }
+        /* -------------------------------------------------------------------------- */
+        labelconfig = {
+            .left = 133,
+            .top = 368,
+            .width = 200,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_FINISH_SPEAKING,
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        finishSpeak = AivoiceListeningLabelInit(labelconfig);
+        if (finishSpeak == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::finishSpeak is nullptr!");
+            return false;
+        }
+        /* -------------------------------------------------------------------------- */
+        showtimeout = new UILabelExt();
+        if (showtimeout == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::showtimeout is nullptr!");
+            return false;
+        }
+        showtimeout->SetPosition(60, 258, 240, 60);
+        showtimeout->SetStyle(STYLE_TEXT_FONT, 50);
+        showtimeout->SetStyle(STYLE_LINE_HEIGHT, 60);
+        showtimeout->SetLineBreakMode(UILabel::LINE_BREAK_ELLIPSIS);
+        showtimeout->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        showtimeout->SetFont(DEFAULT_VECTOR_FONT_FILENAME_EN, 50);
+
+        return true;
+    }
+
+    bool AivoiceListeningView::CreateAivoiceListeningButton(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningButton");
+        ButtonConfig buttonconfig = {
+            .x = 93,
+            .y = 340,
+            .w = 280,
+            .h = 90,
+            .ViewId = FINISH_SPEAKING_BUTTON_VIEW_ID,
+        };
+        finishSpeakButton = AivoiceListeningButtonInit(buttonconfig);
+        if (finishSpeakButton == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "finishSpeakButton new fail!");
+            return false;
+        }
+        UIView::OnTouchListener *touchListener = static_cast<UIView::OnTouchListener *>(AiVoicePresenter::GetInstance());
+        if (touchListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::touchListener can not be nullptr!");
+            return false;
+        }
+        finishSpeakButton->SetOnTouchListener(touchListener);
+
+        return true;
+    }
+
+    bool AivoiceListeningView::CreateAivoiceListeningImageAnimator(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningImageAnimator");
+        AiVoiceListeningPathsArray = CreateImageInfoArray(AIVoiceListeningImagePaths, AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES);
+        if (AiVoiceListeningPathsArray == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::AiVoiceListeningPathsArray  is nullptr!!");
+            return false;
+        }
+
+        ImageAnimatorConfig imageanimatorconfig = {
+            .x = AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_X,
+            .y = AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_Y,
+            .width = AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_W,
+            .height = AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_H,
+            .imageInfoArray = AiVoiceListeningImageInfo,
+            .pathsArray = AiVoiceListeningPathsArray,
+            .numFrames = AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES,
+            .delay = AIVOICE_LISTENING_IMAGE_ANIMATOR_DELAY,
+        };
+        AiVoiceListeningImageAnimatorView = AivoiceListeningImageAnimatorInit(imageanimatorconfig);
+        if (AiVoiceListeningImageAnimatorView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceListeningImageAnimatorView::AiVoiceListeningImageAnimatorView  new fail");
+            return false;
+        }
+
+        return true;
+    }
+
+    UIScrollView *AivoiceListeningView::CreateAivoiceListeningView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningView");
+#if 0
+        if (scrollView == nullptr)
+        {
+            if (!CreateAivoiceListeningScrollView() || !CreateAivoiceListeningLabel() ||
+                !CreateAivoiceListeningButton() || !CreateAivoiceListeningImageAnimator())
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningView fail!!");
+                return nullptr;
+            }
+            scrollView->Add(title);
+            scrollView->Add(AiVoiceListeningImageAnimatorView);
+            scrollView->Add(finishSpeakButton);
+            scrollView->Add(finishSpeak);
+        }
+#else
+        if (!CreateAivoiceListeningScrollView())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningScrollView fail!!");
+        }
+        if (!CreateAivoiceListeningLabel())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningLabel fail!!");
+        }
+        if (!CreateAivoiceListeningButton())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningButton fail!!");
+        }
+        if (!CreateAivoiceListeningImageAnimator())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningImageAnimator fail!!");
+        }
+        if (scrollView == nullptr)
+        {
+            return nullptr;
+        }
+        else
+        {
+            if (title)
+            {
+                scrollView->Add(title);
+            }
+            if (AiVoiceListeningImageAnimatorView)
+            {
+                scrollView->Add(AiVoiceListeningImageAnimatorView);
+            }
+            if (showtimeout)
+            {
+                showtimeout->SetX((scrollView->GetWidth() - showtimeout->GetWidth()) / 2);
+                scrollView->Add(showtimeout);
+            }
+            if (finishSpeakButton)
+            {
+                scrollView->Add(finishSpeakButton);
+            }
+            if (finishSpeak)
+            {
+                scrollView->Add(finishSpeak);
+            }
+            return scrollView;
+        }
+#endif
+    }
+
+    UILabelExt *AivoiceListeningView::GetShowtimeoutLabel(void)
+    {
+        return showtimeout;
+    }
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceMobileDataFailedStartView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceMobileDataFailedStartView.cpp
new file mode 100644 (file)
index 0000000..554cab8
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-05-07 11:25:58
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2025-03-03 11:49:39
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/AiVoice/src/AivoiceMobileDataFailedStartView.cpp
+ */
+#include "aivoice/include/AiVoicePresenter.h"
+#include "aivoice/include/AivoiceMobileDataFailedStartView.h"
+#include "aivoice/include/AiVoiceModel.h"
+#include "wearable_log.h"
+#include "ui_resource_string.h"
+#include <UiConfig.h>
+namespace OHOS
+{
+
+    static AivoiceMobileDataFailedStartView *g_pAivoiceMobileDataFailedStartView{nullptr};
+
+    AivoiceMobileDataFailedStartView::AivoiceMobileDataFailedStartView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::AivoiceMobileDataFailedStartView");
+        g_pAivoiceMobileDataFailedStartView = this;
+    }
+
+    AivoiceMobileDataFailedStartView::~AivoiceMobileDataFailedStartView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::~AivoiceMobileDataFailedStartView");
+        ClearAll();
+        g_pAivoiceMobileDataFailedStartView = nullptr;
+    }
+
+    AivoiceMobileDataFailedStartView *AivoiceMobileDataFailedStartView::GetInstance()
+    {
+        return g_pAivoiceMobileDataFailedStartView;
+    }
+
+    void AivoiceMobileDataFailedStartView::ClearAll(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::ClearAll");
+        if (scrollView != nullptr)
+        {
+            scrollView->RemoveAll();
+
+            if (title != nullptr)
+            {
+                delete title;
+                title = nullptr;
+            }
+
+            if (attentionImage != nullptr)
+            {
+                delete attentionImage;
+                attentionImage = nullptr;
+            }
+
+            for (int i = 0; i < 2; i++)
+            {
+                if (label[i] != nullptr)
+                {
+                    delete label[i];
+                    label[i];
+                }
+            }
+
+            if (ensure != nullptr)
+            {
+                delete ensure;
+                ensure = nullptr;
+            }
+
+            if (ensureButton != nullptr)
+            {
+                delete ensureButton;
+                ensureButton = nullptr;
+            }
+
+            delete scrollView;
+            scrollView = nullptr;
+        }
+    }
+
+    UILabelExt *AivoiceMobileDataFailedStartView::AivoiceMobileDataFailedStartLabelInit(LabelConfig &labelconfig)
+    {
+        UILabelExt *label = new UILabelExt();
+        if (label == nullptr)
+        {
+            return nullptr;
+        }
+        label->SetPosition(labelconfig.left, labelconfig.top, labelconfig.width, labelconfig.height);
+        label->SetStyle(STYLE_TEXT_FONT, labelconfig.fontSize);
+        label->SetStyle(STYLE_LINE_HEIGHT, labelconfig.lineHeigh);
+        //TOOD: 待优化
+        if(labelconfig.textId == STR_DEEPSEEK) {
+            label->SetText("DeepSeek");
+        } else
+            label->SetTextId(labelconfig.textId);
+        label->SetLineBreakMode(labelconfig.lineBreakMode);
+        label->SetRollSpeed(23);
+        label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, labelconfig.fontSize);
+        return label;
+    }
+
+    UIButton *AivoiceMobileDataFailedStartView::AivoiceMobileDataFailedStartButtonInit(ButtonConfig &buttonconfig)
+    {
+        UIButton *button = new UIButton();
+        if (button == nullptr)
+        {
+            return nullptr;
+        }
+        button->SetPosition(buttonconfig.x, buttonconfig.y, buttonconfig.w, buttonconfig.h);
+        button->SetViewId(buttonconfig.ViewId);
+        button->SetStyle(STYLE_BACKGROUND_COLOR, 0xff191919);
+        button->SetStyle(STYLE_BACKGROUND_OPA, 0xff);
+        button->SetStyleForState(STYLE_BACKGROUND_COLOR, 0xff383838, UIButton::PRESSED);
+
+        return button;
+    }
+
+    UIImageView *AivoiceMobileDataFailedStartView::AivoiceMobileDataFailedStartImageInit(ImageConfig &imageconfig)
+    {
+        UIImageView *Image = new UIImageView();
+        if (Image == nullptr)
+        {
+            return nullptr;
+        }
+        Image->SetPosition(imageconfig.x, imageconfig.y, imageconfig.w, imageconfig.h);
+        return Image;
+    }
+
+    bool AivoiceMobileDataFailedStartView::CreateAivoiceMobileDataFailedStartScrollView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::CreateAivoiceMobileDataFailedStartScrollView");
+        scrollView = new UIScrollView();
+        if (scrollView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::scrollView new fail!");
+            return false;
+        }
+        scrollView->SetPosition(0, 0, 466, 466);
+        scrollView->SetTouchable(true);
+        scrollView->SetDraggable(true);
+        UIView::OnDragListener *dragListener = static_cast<UIView::OnDragListener *>(AiVoicePresenter::GetInstance());
+        if (dragListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::dragListener new fail!");
+            return false;
+        }
+        scrollView->SetOnDragListener(dragListener);
+
+        return true;
+    }
+
+    bool AivoiceMobileDataFailedStartView::CreateAivoiceMobileDataFailedStartLabel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::CreateAivoiceMobileDataFailedStartLabel");
+        LabelConfig labelconfig = {
+            .left = 83,
+            .top = 50,
+            .width = 300,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = AiVoiceModel::GetInstance().GetAiModelTextId(),
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        title = AivoiceMobileDataFailedStartLabelInit(labelconfig);
+        if (title == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::title is nullptr!");
+            return false;
+        }
+        /* -------------------------------------------------------------------------- */
+        labelconfig.left = 53;
+        labelconfig.width = 360;
+        int textId[] = {STR_CONNECTION_FAIL, STR_PTALORTM}; /*连接失败,请稍后再重试或更换模型*/
+        for (int i = 0; i < sizeof(textId) / sizeof(textId[0]); i++)
+        {
+            labelconfig.top = 222 + i * 35;
+            labelconfig.textId = textId[i];
+            label[i] = AivoiceMobileDataFailedStartLabelInit(labelconfig);
+            if (label[i] == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::label[%d] is nullptr!", i);
+                return false;
+            }
+        }
+        /* -------------------------------------------------------------------------- */
+        labelconfig = {
+            .left = 133,
+            .top = 368,
+            .width = 200,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_OK,
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        ensure = AivoiceMobileDataFailedStartLabelInit(labelconfig);
+        if (ensure == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::ensure is nullptr!");
+            return false;
+        }
+
+        return true;
+    }
+
+    bool AivoiceMobileDataFailedStartView::CreateAivoiceMobileDataFailedStartButton(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::CreateAivoiceMobileDataFailedStartButton");
+        ButtonConfig buttonconfig = {
+            .x = 93,
+            .y = 340,
+            .w = 280,
+            .h = 90,
+            .ViewId = AIMODEL_CONNECT_FAILED_ENSURE_BUTTON_VIEW_ID,
+        };
+        ensureButton = AivoiceMobileDataFailedStartButtonInit(buttonconfig);
+        if (ensureButton == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ensureButton new fail!");
+            return false;
+        }
+        UIView::OnTouchListener *touchListener = static_cast<UIView::OnTouchListener *>(AiVoicePresenter::GetInstance());
+        if (touchListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::touchListener can not be nullptr!");
+            return false;
+        }
+        ensureButton->SetOnTouchListener(touchListener);
+
+        return true;
+    }
+
+    bool AivoiceMobileDataFailedStartView::CreateAivoiceMobileDataFailedStartImage(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::CreateAivoiceMobileDataFailedStartImage");
+        ImageConfig imageconfig = {
+            .x = 193,
+            .y = 120,
+            .w = 80,
+            .h = 80,
+        };
+        attentionImage = AivoiceMobileDataFailedStartImageInit(imageconfig);
+        if (attentionImage == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "attentionImage new fail!");
+            return false;
+        }
+        attentionImage->SetStyle(STYLE_BORDER_RADIUS, 100);
+        attentionImage->SetSrc(PNG_ATTENTION_IMAGE);
+
+        return true;
+    }
+
+    UIScrollView *AivoiceMobileDataFailedStartView::CreateAivoiceMobileDataFailedStartView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::CreateAivoiceMobileDataFailedStartView");
+        if (scrollView == nullptr)
+        {
+            if (!CreateAivoiceMobileDataFailedStartScrollView() || !CreateAivoiceMobileDataFailedStartLabel() ||
+                !CreateAivoiceMobileDataFailedStartButton() || !CreateAivoiceMobileDataFailedStartImage())
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceMobileDataFailedStartView::CreateAivoiceMobileDataFailedStartView fail!!");
+                return nullptr;
+            }
+            scrollView->Add(title);
+            scrollView->Add(attentionImage);
+            scrollView->Add(label[0]);
+            scrollView->Add(label[1]);
+            scrollView->Add(ensureButton);
+            scrollView->Add(ensure);
+        }
+        return scrollView;
+    }
+
+    void AivoiceMobileDataFailedStartView::UpdateTitleTextId(int textId)
+    {
+        if (title)
+        {
+            if(textId == STR_DEEPSEEK) 
+            {
+                title->SetText("DeepSeek");
+            } 
+            else 
+            {
+            title->SetTextId(textId);
+            title->ForceResetText();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceReturnResultTextView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceReturnResultTextView.cpp
new file mode 100644 (file)
index 0000000..0d5611b
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-05-07 11:25:58
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2025-03-07 09:54:21
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/AiVoice/src/AivoiceReturnResultTextView.cpp
+ */
+#include "aivoice/include/AiVoicePresenter.h"
+#include "aivoice/include/AivoiceReturnResultTextView.h"
+#include "wearable_log.h"
+#include "ui_resource_string.h"
+#include "aivoice/include/AiVoiceModel.h"
+#include <UiConfig.h>
+#include <iostream>
+#include "string"
+
+namespace OHOS
+{
+
+    /* -------------------------------------------------------------------------- */
+    static constexpr const int16_t CHATCONTENT_LIST_X = 53;
+    static constexpr const int16_t CHATCONTENT_LIST_Y = 100;
+    static constexpr const int16_t CHATCONTENT_LIST_W = 360;
+    static constexpr const int16_t CHATCONTENT_LIST_H = 200;
+    static constexpr const int16_t REBOUNDSIZE = 30;
+    static constexpr const int16_t CHATCONTENT_SCROLLBLANKSIZE = 35;
+    static constexpr const int16_t MAX_SCR_DIS = 1000;
+    static constexpr const int16_t SNUM_2 = 2;
+
+    /* -------------------------------------------------------------------------- */
+    static constexpr const int16_t RETURN_BUTTON_X = 73;
+    static constexpr const int16_t RETURN_BUTTON_Y = CHATCONTENT_LIST_Y + CHATCONTENT_LIST_H + 10;
+    static constexpr const int16_t RETURN_BUTTON_W = 100;
+    static constexpr const int16_t RETURN_BUTTON_H = 100;
+    static constexpr const char *RETURN_BUTTON_PATH = "/user/res/AIVoice/AI_Union.bin";
+
+    static constexpr const int16_t CONTINUECHAT_BUTTON_X = 183;
+    static constexpr const int16_t CONTINUECHAT_BUTTON_Y = CHATCONTENT_LIST_Y + CHATCONTENT_LIST_H + 20;
+    static constexpr const int16_t CONTINUECHAT_BUTTON_W = 210;
+    static constexpr const int16_t CONTINUECHAT_BUTTON_H = 100;
+    /* -------------------------------------------------------------------------- */
+    static constexpr const int16_t CONTINUECHAT_X = CONTINUECHAT_BUTTON_X + 45;
+    static constexpr const int16_t CONTINUECHAT_Y = CONTINUECHAT_BUTTON_Y + 33;
+    static constexpr const int16_t CONTINUECHAT_W = 120;
+    static constexpr const int16_t CONTINUECHAT_H = 35;
+
+    static constexpr const int16_t ONE_HALF_NUM = 2;
+
+    static constexpr const int16_t LABEL_ROLL_SPEED = 70;
+
+    static AivoiceReturnResultTextView *g_pAivoiceReturnResultTextView{nullptr};
+
+    AivoiceReturnResultTextView::AivoiceReturnResultTextView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::AivoiceReturnResultTextView");
+        g_pAivoiceReturnResultTextView = this;
+    }
+
+    AivoiceReturnResultTextView::~AivoiceReturnResultTextView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::~AivoiceReturnResultTextView");
+        ClearAll();
+        g_pAivoiceReturnResultTextView = nullptr;
+    }
+
+    AivoiceReturnResultTextView *AivoiceReturnResultTextView::GetInstance()
+    {
+        return g_pAivoiceReturnResultTextView;
+    }
+
+    void AivoiceReturnResultTextView::ClearAll(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::ClearAll");
+        if (scrollView != nullptr)
+        {
+            scrollView->RemoveAll();
+
+            if (title != nullptr)
+            {
+                delete title;
+                title = nullptr;
+            }
+
+            if (chatContentListAdapter != nullptr)
+            {
+                delete chatContentListAdapter;
+                chatContentListAdapter = nullptr;
+            }
+
+            if (chatContentList != nullptr)
+            {
+                delete chatContentList;
+                chatContentList = nullptr;
+            }
+
+            if (returnButton != nullptr)
+            {
+                delete returnButton;
+                returnButton = nullptr;
+            }
+
+            if (continueChatButton != nullptr)
+            {
+                delete continueChatButton;
+                continueChatButton = nullptr;
+            }
+
+            if (continueChat != nullptr)
+            {
+                delete continueChat;
+                continueChat = nullptr;
+            }
+
+            delete scrollView;
+            scrollView = nullptr;
+        }
+    }
+
+    UILabelExt *AivoiceReturnResultTextView::AivoiceReturnResultTextLabelInit(LabelConfig &labelconfig)
+    {
+        UILabelExt *label = new UILabelExt();
+        if (label == nullptr)
+        {
+            return nullptr;
+        }
+        label->SetPosition(labelconfig.left, labelconfig.top, labelconfig.width, labelconfig.height);
+        label->SetStyle(STYLE_TEXT_FONT, labelconfig.fontSize);
+        label->SetStyle(STYLE_LINE_HEIGHT, labelconfig.lineHeight);
+        //TOOD: 待优化
+        if(labelconfig.textId == STR_DEEPSEEK) {
+            label->SetText("DeepSeek");
+        } else
+            label->SetTextId(labelconfig.textId);
+        label->SetLineBreakMode(labelconfig.lineBreakMode);
+        label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, labelconfig.fontSize);
+        label->SetRollSpeed(LABEL_ROLL_SPEED);
+        return label;
+    }
+
+    UIButton *AivoiceReturnResultTextView::AivoiceReturnResultTextButtonInit(ButtonConfig &buttonconfig)
+    {
+        UIButton *button = new UIButton();
+        if (button == nullptr)
+        {
+            return nullptr;
+        }
+        button->SetPosition(buttonconfig.x, buttonconfig.y, buttonconfig.w, buttonconfig.h);
+        button->SetViewId(buttonconfig.ViewId);
+        button->SetStyle(STYLE_BACKGROUND_COLOR, 0xff191919);
+        button->SetStyle(STYLE_BACKGROUND_OPA, 0xff);
+        button->SetStyleForState(STYLE_BACKGROUND_COLOR, 0xff383838, UIButton::PRESSED);
+
+        return button;
+    }
+
+    UIImageView *AivoiceReturnResultTextView::AivoiceReturnResultTextImageInit(ImageConfig &imageconfig)
+    {
+        UIImageView *Image = new UIImageView();
+        if (Image == nullptr)
+        {
+            return nullptr;
+        }
+        Image->SetPosition(imageconfig.x, imageconfig.y, imageconfig.w, imageconfig.h);
+        Image->SetSrc(imageconfig.src);
+        return Image;
+    }
+
+    bool AivoiceReturnResultTextView::CreateAivoiceReturnResultTextScrollView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::CreateAivoiceReturnResultTextScrollView");
+        scrollView = new UIScrollView();
+        if (scrollView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::scrollView new fail!");
+            return false;
+        }
+        scrollView->SetPosition(0, 0, 466, 466);
+        scrollView->SetTouchable(true);
+        scrollView->SetDraggable(true);
+        scrollView->SetDirection(UIScrollView::VERTICAL);
+
+        return true;
+    }
+
+    bool AivoiceReturnResultTextView::CreateAivoiceReturnResultTextLabel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::CreateAivoiceReturnResultTextLabel");
+        LabelConfig labelconfig = {
+            .left = 83,
+            .top = 50,
+            .width = 300,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeight = 35,
+            .textId = AiVoiceModel::GetInstance().GetAiModelTextId(),
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        title = AivoiceReturnResultTextLabelInit(labelconfig);
+        if (title == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::title is nullptr!");
+            return false;
+        }
+        /* -------------------------------------------------------------------------- */
+        labelconfig = {
+            .left = CONTINUECHAT_X,
+            .top = CONTINUECHAT_Y,
+            .width = CONTINUECHAT_W,
+            .height = CONTINUECHAT_H,
+            .fontSize = 30,
+            .lineHeight = 35,
+            .textId = STR_CONTINUE_CHAT,
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        continueChat = AivoiceReturnResultTextLabelInit(labelconfig);
+        if (continueChat == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::continueChat is nullptr!");
+            return false;
+        }
+
+        return true;
+    }
+
+    bool AivoiceReturnResultTextView::CreateAivoiceReturnResultTextList(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::CreateAivoiceReturnResultTextList");
+        chatContentListAdapter = new AivoiceChatContentListAdapter();
+        if (chatContentListAdapter == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::chatContentListAdapter is nullptr");
+            return false;
+        }
+        UIView::OnClickListener *clickListener = static_cast<UIView::OnClickListener *>(AiVoicePresenter::GetInstance());
+        if (clickListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::chatContentListAdapter is nullptr");
+            return false;
+        }
+        chatContentListAdapter->SetItemClickListener(clickListener);
+
+        chatContentList = new UIList(UIList::VERTICAL);
+        if (chatContentList == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SettingView::OnStart::chatContentList is nullptr");
+            return false;
+        }
+        chatContentList->SetPosition(CHATCONTENT_LIST_X, CHATCONTENT_LIST_Y, CHATCONTENT_LIST_W, CHATCONTENT_LIST_H);
+        chatContentList->SetStyle(STYLE_BACKGROUND_COLOR, 0xff000000);
+        chatContentList->EnableAutoAlign(true);
+        chatContentList->SetTouchable(true);
+        chatContentList->SetDraggable(true);
+        chatContentList->SetThrowDrag(true);
+        // chatContentList->SetReboundSize(REBOUNDSIZE);
+        chatContentList->SetMaxScrollDistance(MAX_SCR_DIS);
+        chatContentList->SetSwipeACCLevel(200); // 800: compensation distance
+        chatContentList->SetDragACCLevel(5);    // 5: drag acceleration
+        chatContentList->SetRotateFactor(2);
+        chatContentList->RequestFocus();
+        // chatContentList->SetIntercept(true);
+        chatContentList->SetAdapter(chatContentListAdapter);
+        chatContentList->RefreshList();
+        /* -------------------------------------------------------------------------- */
+        // AiVoiceModel::GetInstance().InitchatContentItems();
+        /* -------------------------------------------------------------------------- */
+        return true;
+    }
+
+    bool AivoiceReturnResultTextView::CreateAivoiceReturnResultTextButton(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::CreateAivoiceReturnResultTextButton");
+        ButtonConfig buttonconfig = {
+            .x = RETURN_BUTTON_X,
+            .y = RETURN_BUTTON_Y,
+            .w = RETURN_BUTTON_W,
+            .h = RETURN_BUTTON_H,
+            .ViewId = AIVOICERETURNRESULTTEXT_RETURN_BUTTON_VIEW_ID,
+        };
+        returnButton = AivoiceReturnResultTextButtonInit(buttonconfig);
+        if (returnButton == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "returnButton new fail!");
+            return false;
+        }
+        returnButton->SetImagePosition(39, 39);
+        returnButton->SetImageSrc(RETURN_BUTTON_PATH, RETURN_BUTTON_PATH);
+        UIView::OnTouchListener *touchListener = static_cast<UIView::OnTouchListener *>(AiVoicePresenter::GetInstance());
+        if (touchListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::touchListener can not be nullptr!");
+            return false;
+        }
+        returnButton->SetOnTouchListener(touchListener);
+        /* -------------------------------------------------------------------------- */
+        buttonconfig = {
+            .x = CONTINUECHAT_BUTTON_X,
+            .y = CONTINUECHAT_BUTTON_Y,
+            .w = CONTINUECHAT_BUTTON_W,
+            .h = CONTINUECHAT_BUTTON_H,
+            .ViewId = AIVOICERETURNRESULTTEXT_CONTINUECHAT_BUTTON_VIEW_ID,
+        };
+        continueChatButton = AivoiceReturnResultTextButtonInit(buttonconfig);
+        if (continueChatButton == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "continueChatButton new fail!");
+            return false;
+        }
+        continueChatButton->SetOnTouchListener(touchListener);
+
+        return true;
+    }
+
+    UIScrollView *AivoiceReturnResultTextView::CreateAivoiceReturnResultTextView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::CreateAivoiceReturnResultTextView");
+        if (scrollView == nullptr)
+        {
+            if (!CreateAivoiceReturnResultTextScrollView() || !CreateAivoiceReturnResultTextLabel() ||
+                !CreateAivoiceReturnResultTextList() || !CreateAivoiceReturnResultTextButton())
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::CreateAivoiceReturnResultTextView fail!!");
+                return nullptr;
+            }
+            /* ----------------------------------- Add ---------------------------------- */
+            scrollView->Add(title);
+            scrollView->Add(chatContentList);
+            scrollView->Add(returnButton);
+            scrollView->Add(continueChatButton);
+            scrollView->Add(continueChat);
+        }
+        return scrollView;
+    }
+
+    /*添加对话内容到List*/
+    void AivoiceReturnResultTextView::AddChatContentToList(const ChatContentItem &item)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::AddChatContentToList");
+        chatContentListAdapter->AddListItem(item);
+    }
+
+    AivoiceChatContentListAdapter *AivoiceReturnResultTextView::GetAivoiceChatContentListAdapter(void)
+    {
+        return chatContentListAdapter;
+    }
+
+    UIList *AivoiceReturnResultTextView::GetChatContentList(void)
+    {
+        return chatContentList;
+    }
+
+    void AivoiceReturnResultTextView::UpdateTitleTextId(int textId)
+    {
+        if (title)
+        {
+            if(textId == STR_DEEPSEEK) 
+            {
+                title->SetText("DeepSeek");
+            } 
+            else 
+            {
+            title->SetTextId(textId);
+            title->ForceResetText();
+            }
+        }
+    }
+
+    void AivoiceReturnResultTextView::IsScrollChatContentList(bool isScroll)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceReturnResultTextView::IsScrollChatContentList");
+        if (isScroll)
+        {
+            scrollView->RequestFocus();
+            chatContentList->SetTouchable(false);
+            chatContentList->SetDraggable(false);
+        }
+        else
+        {
+            chatContentList->RequestFocus();
+            chatContentList->SetTouchable(true);
+            chatContentList->SetDraggable(true);
+        }
+    }
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceThinkingView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AivoiceThinkingView.cpp
new file mode 100644 (file)
index 0000000..6e7db53
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-05-07 11:25:58
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-11-05 11:18:14
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/AiVoice/src/AivoiceThinkingView.cpp
+ */
+#include "aivoice/include/AiVoicePresenter.h"
+#include "aivoice/include/AivoiceThinkingView.h"
+#include "wearable_log.h"
+#include "ui_resource_string.h"
+#include <UiConfig.h>
+#include "uicomponents/UIComponents.h"
+// #include "common/image_cache_manager.h"
+namespace OHOS
+{
+
+    static AivoiceThinkingView *g_pAivoiceThinkingView{nullptr};
+
+    AivoiceThinkingView::AivoiceThinkingView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::AivoiceThinkingView");
+        g_pAivoiceThinkingView = this;
+    }
+
+    AivoiceThinkingView::~AivoiceThinkingView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::~AivoiceThinkingView");
+        ClearAll();
+        g_pAivoiceThinkingView = nullptr;
+    }
+
+    AivoiceThinkingView *AivoiceThinkingView::GetInstance()
+    {
+        return g_pAivoiceThinkingView;
+    }
+
+    void AivoiceThinkingView::ClearAll(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::ClearAll");
+        if (scrollView != nullptr)
+        {
+            scrollView->RemoveAll();
+
+            if (title != nullptr)
+            {
+                delete title;
+                title = nullptr;
+            }
+
+            if (AiVoiceThinkingImageAnimatorView != nullptr)
+            {
+                AiVoiceThinkingImageAnimatorView->Stop();
+                delete AiVoiceThinkingImageAnimatorView;
+                AiVoiceThinkingImageAnimatorView = nullptr;
+
+                // FreeImagePathsArray(AiVoiceThinkingPathsArray, AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES);
+                FreeImageInfoArray(AiVoiceThinkingPathsArray, AIVoiceThinkingImagePaths, AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES);
+            }
+
+            if (cancelThink != nullptr)
+            {
+                delete cancelThink;
+                cancelThink = nullptr;
+            }
+
+            if (cancelThinkButton != nullptr)
+            {
+                delete cancelThinkButton;
+                cancelThinkButton = nullptr;
+            }
+
+            delete scrollView;
+            scrollView = nullptr;
+        }
+    }
+
+    UILabelExt *AivoiceThinkingView::AivoiceThinkingLabelInit(LabelConfig &labelconfig)
+    {
+        UILabelExt *label = new UILabelExt();
+        if (label == nullptr)
+        {
+            return nullptr;
+        }
+        label->SetPosition(labelconfig.left, labelconfig.top, labelconfig.width, labelconfig.height);
+        label->SetStyle(STYLE_TEXT_FONT, labelconfig.fontSize);
+        label->SetStyle(STYLE_LINE_HEIGHT, labelconfig.lineHeigh);
+        label->SetTextId(labelconfig.textId);
+        label->SetLineBreakMode(labelconfig.lineBreakMode);
+        label->SetRollSpeed(23);
+        label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, labelconfig.fontSize);
+        return label;
+    }
+
+    UIButton *AivoiceThinkingView::AivoiceThinkingButtonInit(ButtonConfig &buttonconfig)
+    {
+        UIButton *button = new UIButton();
+        if (button == nullptr)
+        {
+            return nullptr;
+        }
+        button->SetPosition(buttonconfig.x, buttonconfig.y, buttonconfig.w, buttonconfig.h);
+        button->SetViewId(buttonconfig.ViewId);
+        button->SetStyle(STYLE_BACKGROUND_COLOR, 0xff191919);
+        button->SetStyle(STYLE_BACKGROUND_OPA, 0xff);
+        button->SetStyleForState(STYLE_BACKGROUND_COLOR, 0xff383838, UIButton::PRESSED);
+
+        return button;
+    }
+
+    UIImageAnimatorView *AivoiceThinkingView::AivoiceThinkingImageAnimatorInit(ImageAnimatorConfig &imageanimatorconfig)
+    {
+        UIImageAnimatorView *animatorView = new UIImageAnimatorView();
+        if (animatorView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceThinkingImageAnimatorView::AiVoiceThinkingImageAnimatorView new fail");
+            return nullptr;
+        }
+
+        for (uint8_t i = 0; i < imageanimatorconfig.numFrames; i++)
+        {
+            imageanimatorconfig.imageInfoArray[i].imageInfo = (imageanimatorconfig.pathsArray[i]);
+            // imageanimatorconfig.imageInfoArray[i].imagePath = (imageanimatorconfig.pathsArray[i]);
+            // imageanimatorconfig.imageInfoArray[i].imageType = IMG_SRC_FILE_PATH;
+            imageanimatorconfig.imageInfoArray[i].imageType = IMG_SRC_IMAGE_INFO;
+            imageanimatorconfig.imageInfoArray[i].pos.x = imageanimatorconfig.x;
+            imageanimatorconfig.imageInfoArray[i].pos.y = imageanimatorconfig.y;
+            imageanimatorconfig.imageInfoArray[i].width = imageanimatorconfig.width;
+            imageanimatorconfig.imageInfoArray[i].height = imageanimatorconfig.height;
+        }
+
+        animatorView->SetPosition(imageanimatorconfig.x, imageanimatorconfig.y, imageanimatorconfig.width, imageanimatorconfig.height);
+        animatorView->SetImageAnimatorSrc(imageanimatorconfig.imageInfoArray, imageanimatorconfig.numFrames, imageanimatorconfig.delay);
+        animatorView->SetRepeat(true);
+        animatorView->SetSizeFixed(true);
+        // animatorView->SetAutoEnable(false);
+        // animatorView->SetResizeMode(UIImageAnimatorView::FILL);
+        animatorView->Start();
+
+        return animatorView;
+    }
+
+    bool AivoiceThinkingView::CreateAivoiceThinkingScrollView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::CreateAivoiceThinkingScrollView");
+        scrollView = new UIScrollView();
+        if (scrollView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::scrollView new fail!");
+            return false;
+        }
+        scrollView->SetPosition(0, 0, 466, 466);
+        UIView::OnDragListener *dragListener = static_cast<UIView::OnDragListener *>(AiVoicePresenter::GetInstance());
+        if (dragListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::dragListener new fail!");
+            return false;
+        }
+        scrollView->SetOnDragListener(dragListener);
+        scrollView->SetTouchable(true);
+        scrollView->SetDraggable(true);
+
+        return true;
+    }
+
+    bool AivoiceThinkingView::CreateAivoiceThinkingLabel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::CreateAivoiceThinkingLabel");
+        LabelConfig labelconfig = {
+            .left = 83,
+            .top = 50,
+            .width = 300,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_THINKING,
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        title = AivoiceThinkingLabelInit(labelconfig);
+        if (title == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::title is nullptr!");
+            return false;
+        }
+        /* -------------------------------------------------------------------------- */
+        labelconfig = {
+            .left = 133,
+            .top = 368,
+            .width = 200,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_CANCEL,
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        cancelThink = AivoiceThinkingLabelInit(labelconfig);
+        if (cancelThink == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::cancelThink is nullptr!");
+            return false;
+        }
+        cancelThink->SetTextColor(Color::GetColorFromRGBA(0xfd, 0x52, 0x03, 0xff));
+
+        return true;
+    }
+
+    bool AivoiceThinkingView::CreateAivoiceThinkingButton(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::CreateAivoiceThinkingButton");
+        ButtonConfig buttonconfig = {
+            .x = 93,
+            .y = 340,
+            .w = 280,
+            .h = 90,
+            .ViewId = CANCEL_THINKING_BUTTON_VIEW_ID,
+        };
+        cancelThinkButton = AivoiceThinkingButtonInit(buttonconfig);
+        if (cancelThinkButton == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "cancelThinkButton new fail!");
+            return false;
+        }
+        UIView::OnTouchListener *touchListener = static_cast<UIView::OnTouchListener *>(AiVoicePresenter::GetInstance());
+        if (touchListener == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::touchListener can not be nullptr!");
+            return false;
+        }
+        cancelThinkButton->SetOnTouchListener(touchListener);
+
+        return true;
+    }
+
+    bool AivoiceThinkingView::CreateAivoiceThinkingImageAnimator(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::CreateAivoiceThinkingImageAnimator");
+        AiVoiceThinkingPathsArray = CreateImageInfoArray(AIVoiceThinkingImagePaths, AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES);
+        if (AiVoiceThinkingPathsArray == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::AiVoiceThinkingPathsArray  is nullptr!!");
+            return false;
+        }
+
+        ImageAnimatorConfig imageanimatorconfig = {
+            .x = AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_X,
+            .y = AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_Y,
+            .width = AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_W,
+            .height = AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_H,
+            .imageInfoArray = AiVoiceThinkingImageInfo,
+            .pathsArray = AiVoiceThinkingPathsArray,
+            .numFrames = AIVOICE_THINKING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES,
+            .delay = AIVOICE_THINKING_IMAGE_ANIMATOR_DELAY,
+        };
+        AiVoiceThinkingImageAnimatorView = AivoiceThinkingImageAnimatorInit(imageanimatorconfig);
+        if (AiVoiceThinkingImageAnimatorView == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceThinkingImageAnimatorView::AiVoiceThinkingImageAnimatorView  new fail");
+            return false;
+        }
+
+        return true;
+    }
+
+    UIScrollView *AivoiceThinkingView::CreateAivoiceThinkingView(void)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::CreateAivoiceThinkingView");
+#if 0
+        if (scrollView == nullptr)
+        {
+            if (!CreateAivoiceThinkingScrollView() || !CreateAivoiceThinkingLabel() ||
+                !CreateAivoiceThinkingButton() || !CreateAivoiceThinkingImageAnimator())
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::CreateAivoiceThinkingView fail!!");
+                return nullptr;
+            }
+            
+            scrollView->Add(title);
+            scrollView->Add(AiVoiceThinkingImageAnimatorView);
+            scrollView->Add(cancelThinkButton);
+            scrollView->Add(cancelThink);
+        }
+#endif
+        if (!CreateAivoiceThinkingScrollView())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::CreateAivoiceThinkingScrollView fail!!");
+        }
+        if (!CreateAivoiceThinkingLabel())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::CreateAivoiceThinkingLabel fail!!");
+        }
+        if (!CreateAivoiceThinkingButton())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::CreateAivoiceThinkingButton fail!!");
+        }
+        if (!CreateAivoiceThinkingImageAnimator())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::CreateAivoiceThinkingImageAnimator fail!!");
+        }
+
+        if (scrollView != nullptr)
+        {
+            if (title != nullptr)
+            {
+                scrollView->Add(title);
+            }
+            if (AiVoiceThinkingImageAnimatorView != nullptr)
+            {
+                scrollView->Add(AiVoiceThinkingImageAnimatorView);
+            }
+            if (cancelThinkButton != nullptr)
+            {
+                scrollView->Add(cancelThinkButton);
+            }
+            if (cancelThink != nullptr)
+            {
+                scrollView->Add(cancelThink);
+            }
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceThinkingView::CreateAivoiceThinkingView success!!");
+            return scrollView;
+        }
+        else
+        {
+            return nullptr;
+        }
+    }
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/ApiKeysDeleteView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/ApiKeysDeleteView.cpp
new file mode 100644 (file)
index 0000000..0d2138a
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-07-29 16:03:58
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-07-30 16:22:42
+ * @FilePath: /xts_origin/FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/src/apikeys/ApiKeysDeleteView.cpp
+ */
+
+#include "aivoice/include/apikeys/ApiKeysDeleteView.h"
+#include "aivoice/include/apikeys/ApiKeysPresenter.h"
+#include "wearable_log.h"
+#include "ui_resource_string.h"
+#include "UiConfig.h"
+namespace OHOS
+{
+    ApiKeysDeleteView::ApiKeysDeleteView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::ApiKeysDeleteView");
+    }
+
+    ApiKeysDeleteView::~ApiKeysDeleteView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::~ApiKeysDeleteView");
+        ClearAll();
+    }
+
+    void ApiKeysDeleteView::ClearAll(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::ClearAll");
+
+        if (ApiKeysDeleteScrollView != nullptr)
+        {
+            ApiKeysDeleteScrollView->RemoveAll();
+            if (clickListener != nullptr)
+            {
+                delete clickListener;
+                clickListener = nullptr;
+            }
+            if (dragListener != nullptr)
+            {
+                delete dragListener;
+                dragListener = nullptr;
+            }
+            if (ApiKeysDeleteTitleLabel != nullptr)
+            {
+                delete ApiKeysDeleteTitleLabel;
+                ApiKeysDeleteTitleLabel = nullptr;
+            }
+
+            if (ApiKeysDeleteNoteLabel != nullptr)
+            {
+                delete ApiKeysDeleteNoteLabel;
+                ApiKeysDeleteNoteLabel = nullptr;
+            }
+            if (ApiKeysDeleteButton != nullptr)
+            {
+                delete ApiKeysDeleteButton;
+                ApiKeysDeleteButton = nullptr;
+            }
+            if (ApiKeysCancelDeleteButton != nullptr)
+            {
+                delete ApiKeysCancelDeleteButton;
+                ApiKeysCancelDeleteButton = nullptr;
+            }
+            delete ApiKeysDeleteScrollView;
+            ApiKeysDeleteScrollView = nullptr;
+        }
+    }
+
+    UILabelExt *ApiKeysDeleteView::ApiKeysDeleteViewLabelInit(LabelConfig &labelconfig)
+    {
+        UILabelExt *label = new UILabelExt();
+        if (label == nullptr)
+        {
+            return nullptr;
+        }
+        label->SetPosition(labelconfig.left, labelconfig.top, labelconfig.width, labelconfig.height);
+        label->SetStyle(STYLE_TEXT_FONT, labelconfig.fontSize);
+        label->SetStyle(STYLE_LINE_HEIGHT, labelconfig.lineHeigh);
+        label->SetTextId(labelconfig.textId);
+        label->SetLineBreakMode(labelconfig.lineBreakMode);
+        label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label->SetRollSpeed(23);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, labelconfig.fontSize);
+        return label;
+    }
+
+    bool ApiKeysDeleteView::CreateApiKeysDeleteViewLabel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CreateAiVoiceViewLabel");
+        LabelConfig labelConfig = {
+            .left = 83,
+            .top = 50,
+            .width = 300,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_API_KEYS, /*API Keys*/
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        ApiKeysDeleteTitleLabel = ApiKeysDeleteViewLabelInit(labelConfig);
+        if (ApiKeysDeleteTitleLabel == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::ApiKeysDeleteTitleLabel new fail!");
+            return false;
+        }
+        ApiKeysDeleteScrollView->Add(ApiKeysDeleteTitleLabel);
+        /* -------------------------------------------------------------------------- */
+        labelConfig.textId = STR_DYWTDAK;
+        labelConfig.top = 187;
+        ApiKeysDeleteNoteLabel = ApiKeysDeleteViewLabelInit(labelConfig);
+        if (ApiKeysDeleteNoteLabel == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::ApiKeysDeleteNoteLabel new fail!");
+            return false;
+        }
+        ApiKeysDeleteNoteLabel->SetTextColor(Color::GetColorFromRGBA(0x99, 0x99, 0x99, 0xff));
+
+        ApiKeysDeleteScrollView->Add(ApiKeysDeleteNoteLabel);
+
+        return true;
+    }
+
+    /*删除API Keys视图*/
+    UIScrollView *ApiKeysDeleteView::CreateApiKeysDeleteView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::CreateApiKeysDeleteView");
+        if (ApiKeysDeleteScrollView == nullptr)
+        {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::CreateAiVoiceScrollView");
+            ApiKeysDeleteScrollView = new UIScrollView();
+            if (ApiKeysDeleteScrollView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::CreateApiKeysDeleteScrollView new fail!");
+                return nullptr;
+            }
+            ApiKeysDeleteScrollView->SetPosition(0, 0, 466, 466);
+            ApiKeysDeleteScrollView->SetViewId(APIKEYS_DELETE_SCROLLVIEW_VIEWID);
+            ApiKeysDeleteScrollView->SetTouchable(true);
+            ApiKeysDeleteScrollView->SetDraggable(true);
+            if (dragListener == nullptr)
+            {
+                dragListener = new ApiKeysPresenter();
+                if (dragListener == nullptr)
+                {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::dragListener new fail!");
+                }
+            }
+            ApiKeysDeleteScrollView->SetOnDragListener(dragListener);
+            /* -------------------------------------------------------------------------- */
+            ApiKeysCancelDeleteButton = new UIButton();
+            if (ApiKeysCancelDeleteButton == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::ApiKeysCancelDeleteButton new fail!");
+                return nullptr;
+            }
+            ApiKeysCancelDeleteButton->SetPosition(111, 299, 100, 100);
+            ApiKeysCancelDeleteButton->SetViewId(APIKEYS_CANCEL_DELETE_BUTTON_VIEWID);
+            ApiKeysCancelDeleteButton->SetImageSrc(PNG_SYSTEM_CHECK_OFF_IMAGE,PNG_SYSTEM_CHECK_OFF_IMAGE);
+            ApiKeysCancelDeleteButton->SetStyle(STYLE_BACKGROUND_COLOR, 0xff000000);
+            ApiKeysCancelDeleteButton->SetStyle(STYLE_BACKGROUND_OPA, 0x00);
+            ApiKeysCancelDeleteButton->SetStyleForState(STYLE_BACKGROUND_COLOR, 0xff383838, UIButton::PRESSED);
+            ApiKeysDeleteScrollView->Add(ApiKeysCancelDeleteButton);
+            /* -------------------------------------------------------------------------- */
+            ApiKeysDeleteButton = new UIButton();
+            if (ApiKeysDeleteButton == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::ApiKeysDeleteButton new fail!");
+                return nullptr;
+            }
+            ApiKeysDeleteButton->SetPosition(256, 299, 100, 100);
+            ApiKeysDeleteButton->SetViewId(APIKEYS_DELETE_BUTTON_VIEWID);
+            ApiKeysDeleteButton->SetImageSrc(PNG_SYSTEM_CHECK_ON_IMAGE,PNG_SYSTEM_CHECK_ON_IMAGE);
+            ApiKeysDeleteButton->SetStyle(STYLE_BACKGROUND_COLOR, 0xff000000);
+            ApiKeysDeleteButton->SetStyle(STYLE_BACKGROUND_OPA, 0x00);
+            ApiKeysDeleteButton->SetStyleForState(STYLE_BACKGROUND_COLOR, 0xff383838, UIButton::PRESSED);
+            ApiKeysDeleteScrollView->Add(ApiKeysDeleteButton);
+            /* -------------------------------------------------------------------------- */
+            if (clickListener == nullptr)
+            {
+                clickListener = new ApiKeysPresenter();
+                if (clickListener == nullptr)
+                {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ApiKeysDeleteView::clickListener new fail!");
+                }
+            }
+            ApiKeysCancelDeleteButton->SetOnClickListener(clickListener);
+            ApiKeysDeleteButton->SetOnClickListener(clickListener);
+            /* -------------------------------------------------------------------------- */
+            if (!CreateApiKeysDeleteViewLabel())
+            {
+                return nullptr;
+            }
+        }
+        return ApiKeysDeleteScrollView;
+    }
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/ApiKeysPresenter.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/ApiKeysPresenter.cpp
new file mode 100644 (file)
index 0000000..cdea2d3
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-07-29 16:14:16
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-09-07 12:19:09
+ * @FilePath: /xts_origin/FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/src/apikeys/ApiKeysPresenter.cpp
+ */
+
+#include "aivoice/include/apikeys/ApiKeysPresenter.h"
+#include "aivoice/include/apikeys/SetApiKeysView.h"
+#include "aivoice/include/apikeys/NotSetApiKeysView.h"
+#include "aivoice/include/AiVoiceView.h"
+#include "aivoice/include/AiVoiceModel.h"
+#include "wearable_log.h"
+#include "UiConfig.h"
+#include "iostream"
+#include "string"
+#include "map"
+namespace OHOS
+{
+
+    static ApiKeysPresenter *g_pApiKeysPresenter = nullptr;
+    ApiKeysPresenter::ApiKeysPresenter()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ApiKeysPresenter::ApiKeysPresenter");
+        g_pApiKeysPresenter = this;
+    }
+
+    ApiKeysPresenter::~ApiKeysPresenter()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ApiKeysPresenter::ApiKeysPresenter");
+        g_pApiKeysPresenter = nullptr;
+    }
+
+    ApiKeysPresenter *ApiKeysPresenter::GetInstance()
+    {
+        return g_pApiKeysPresenter;
+    }
+
+    bool ApiKeysPresenter::OnClick(UIView &view, const ClickEvent &event)
+    {
+        UNUSED(event);
+        std::string viewId = view.GetViewId();
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ApiKeysPresenter::OnClick ,viewId = %s", viewId.c_str());
+
+        AiVoiceModel::GetInstance().reset_ai_screen60s_timer_time(); // 重置60s取消常亮屏timer
+
+        AiVoiceView *p_AiVoiceView = AiVoiceView::GetInstance();
+
+        std::map<std::string, std::pair<int, int>> viewMap = {
+            {SETAPIKEYS_DELETE_BUTTON_VIEWID, {AIVOICE_SETAPIKEYS, AIVOICE_APIKEYS_DELETE}},         /*进入到删除apikeys界面*/
+            {NOTSETAPIKEYS_ENSURE_BUTTON_VIEWID, {AIVOICE_NOTSETAPIKEYS, AIVOICE_STARTCHAT_VIEWID}}, /*退到AI对话界面*/
+            {APIKEYS_DELETE_BUTTON_VIEWID, {AIVOICE_APIKEYS_DELETE, AIVOICE_STARTCHAT_VIEWID}},      /*删除完apikeys退到AI对话界面*/
+            {APIKEYS_CANCEL_DELETE_BUTTON_VIEWID, {AIVOICE_APIKEYS_DELETE, AIVOICE_SETAPIKEYS}},     /*退到已设置apikeys界面*/
+        };
+
+        auto it = viewMap.find(viewId);
+        if (it != viewMap.end() && p_AiVoiceView != nullptr)
+        {
+            if (it->first == APIKEYS_DELETE_BUTTON_VIEWID)
+            {
+                AiVoiceModel::GetInstance().DeleteLocalOpenAIAPIKeys(); /*删除本地APIKeys*/
+            }
+            p_AiVoiceView->ChangeView(it->second.first, it->second.second);
+        }
+        return true;
+    }
+
+    bool ApiKeysPresenter::OnDrag(UIView &view, const DragEvent &event)
+    {
+        UNUSED(view);
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ApiKeysPresenter::OnDrag");
+        if ((event.GetDeltaX() > X_DRAG_OFFSET) && (event.GetDeltaX() > (DOUBLES * MATH_ABS(event.GetDeltaY())))) // 拖动过程中判断是否是水平滑动
+        {
+            ApiKeysPresenter::X_DRAG_FLAG = true;
+        }
+        return true;
+    }
+
+    bool ApiKeysPresenter::OnDragEnd(UIView &view, const DragEvent &event)
+    {
+        UNUSED(view);
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ApiKeysPresenter::OnDragEnd");
+        std::string viewId = view.GetViewId();
+        AiVoiceView *p_AiVoiceView = AiVoiceView::GetInstance();
+        if (p_AiVoiceView == nullptr)
+        {
+            return false;
+        }
+        if (event.GetDragDirection() == DragEvent::DIRECTION_LEFT_TO_RIGHT && X_DRAG_FLAG)
+        {
+            std::map<std::string, std::pair<int, int>> viewMap = {
+                // {SETAPIKEYS_SCROLLVIEW_VIEWID, {AIVOICE_SETAPIKEYS, AIVOICE_STARTCHAT_VIEWID}},
+                // {NOTSETAPIKEYS_SCROLLVIEW_VIEWID, {AIVOICE_NOTSETAPIKEYS, AIVOICE_STARTCHAT_VIEWID}},
+                {APIKEYS_DELETE_SCROLLVIEW_VIEWID, {AIVOICE_APIKEYS_DELETE, AIVOICE_SETAPIKEYS}},
+            };
+
+            auto it = viewMap.find(viewId);
+            if (it != viewMap.end())
+            {
+                p_AiVoiceView->ChangeView(it->second.first, it->second.second);
+            }
+            X_DRAG_FLAG = false;
+        }
+        else if (event.GetDragDirection() == DragEvent::DIRECTION_TOP_TO_BOTTOM) /*下滑*/
+        {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "DIRECTION_TOP_TO_BOTTOM");
+            if (viewId == SETAPIKEYS_SCROLLVIEW_VIEWID)
+            {
+                p_AiVoiceView->ChangeView(AIVOICE_SETAPIKEYS, AIVOICE_STARTCHAT_VIEWID); /*API Keys set界面->开始对话界面*/
+            }
+            else if (viewId == NOTSETAPIKEYS_SCROLLVIEW_VIEWID)
+            {
+                p_AiVoiceView->ChangeView(AIVOICE_NOTSETAPIKEYS, AIVOICE_STARTCHAT_VIEWID); /*API Keys notset界面->开始对话界面*/
+            }
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/NotSetApiKeysView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/NotSetApiKeysView.cpp
new file mode 100644 (file)
index 0000000..6c4c11d
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-07-29 16:04:23
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-11-05 11:20:24
+ * @FilePath: /xts_origin/FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/src/apikeys/NotSetApiKeysView.cpp
+ */
+
+#include "aivoice/include/apikeys/NotSetApiKeysView.h"
+#include "aivoice/include/apikeys/ApiKeysPresenter.h"
+#include "wearable_log.h"
+#include "ui_resource_string.h"
+namespace OHOS
+{
+    NotSetApiKeysView::NotSetApiKeysView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::NotSetApiKeysView");
+    }
+
+    NotSetApiKeysView::~NotSetApiKeysView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::~NotSetApiKeysView");
+        ClearAll();
+    }
+
+    void NotSetApiKeysView::ClearAll(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::ClearAll");
+
+        if (NotSetApiKeysScrollView != nullptr)
+        {
+            NotSetApiKeysScrollView->RemoveAll();
+            if (clickListener != nullptr)
+            {
+                delete clickListener;
+                clickListener = nullptr;
+            }
+            if (dragListener != nullptr)
+            {
+                delete dragListener;
+                dragListener = nullptr;
+            }
+            if (NotSetApiKeysTitleLabel != nullptr)
+            {
+                delete NotSetApiKeysTitleLabel;
+                NotSetApiKeysTitleLabel = nullptr;
+            }
+            for (int i = 0; i < static_cast<int>(sizeof(NotSetApiKeysNoteLabel) / sizeof(NotSetApiKeysNoteLabel[0])); i++)
+            {
+                if (NotSetApiKeysNoteLabel[i] != nullptr)
+                {
+                    delete NotSetApiKeysNoteLabel[i];
+                    NotSetApiKeysNoteLabel[i] = nullptr;
+                }
+            }
+            if (NotSetApiKeysEnsureLabel != nullptr)
+            {
+                delete NotSetApiKeysEnsureLabel;
+                NotSetApiKeysEnsureLabel = nullptr;
+            }
+            if (NotSetApiKeysEnsureButton != nullptr)
+            {
+                delete NotSetApiKeysEnsureButton;
+                NotSetApiKeysEnsureButton = nullptr;
+            }
+            delete NotSetApiKeysScrollView;
+            NotSetApiKeysScrollView = nullptr;
+        }
+    }
+
+    UILabelExt *NotSetApiKeysView::NotSetApiKeysViewLabelInit(LabelConfig &labelconfig)
+    {
+        UILabelExt *label = new UILabelExt();
+        if (label == nullptr)
+        {
+            return nullptr;
+        }
+        label->SetPosition(labelconfig.left, labelconfig.top, labelconfig.width, labelconfig.height);
+        label->SetStyle(STYLE_TEXT_FONT, labelconfig.fontSize);
+        label->SetStyle(STYLE_LINE_HEIGHT, labelconfig.lineHeigh);
+        label->SetTextId(labelconfig.textId);
+        label->SetLineBreakMode(labelconfig.lineBreakMode);
+        label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label->SetRollSpeed(23);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, labelconfig.fontSize);
+        return label;
+    }
+
+    bool NotSetApiKeysView::CreateNotSetApiKeysViewLabel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceView::CreateAiVoiceViewLabel");
+        LabelConfig labelConfig = {
+            .left = 83,
+            .top = 50,
+            .width = 300,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_API_KEYS, /*API Keys*/
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        NotSetApiKeysTitleLabel = NotSetApiKeysViewLabelInit(labelConfig);
+        if (NotSetApiKeysTitleLabel == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::NotSetApiKeysTitleLabel new fail!");
+            return false;
+        }
+        NotSetApiKeysScrollView->Add(NotSetApiKeysTitleLabel);
+        /* -------------------------------------------------------------------------- */
+        int textId[] = {STR_PGTTAF, STR_DAFBS, STR_OPENAI_API_KEYS};
+        for (int i = 0; i < static_cast<int>((sizeof(textId) / sizeof(textId[0]))); i++)
+        {
+            labelConfig.left = 53;
+            labelConfig.top = 161 + i * 35;
+            labelConfig.width = 360;
+            labelConfig.textId = textId[i];
+            NotSetApiKeysNoteLabel[i] = NotSetApiKeysViewLabelInit(labelConfig);
+            if (NotSetApiKeysNoteLabel[i] == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::NotSetApiKeysNoteLabel[%d] new fail!", i);
+                return false;
+            }
+            NotSetApiKeysScrollView->Add(NotSetApiKeysNoteLabel[i]);
+        }
+        /* -------------------------------------------------------------------------- */
+        labelConfig.left = 133;
+        labelConfig.top = 368;
+        labelConfig.width = 200;
+        labelConfig.textId = STR_OK; /*确定*/
+        NotSetApiKeysEnsureLabel = NotSetApiKeysViewLabelInit(labelConfig);
+        if (NotSetApiKeysEnsureLabel == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::NotSetApiKeysEnsureLabel new fail!");
+            return false;
+        }
+        NotSetApiKeysScrollView->Add(NotSetApiKeysEnsureLabel);
+        return true;
+    }
+
+    /*未配置了API Keys视图*/
+    UIScrollView *NotSetApiKeysView::CreateNotSetApiKeysView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::CreateNotSetApiKeysView");
+        if (NotSetApiKeysScrollView == nullptr)
+        {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::CreateAiVoiceScrollView");
+            NotSetApiKeysScrollView = new UIScrollView();
+            if (NotSetApiKeysScrollView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::CreateNotSetApiKeysScrollView new fail!");
+                return nullptr;
+            }
+            NotSetApiKeysScrollView->SetPosition(0, 0, 466, 466);
+            NotSetApiKeysScrollView->SetViewId(NOTSETAPIKEYS_SCROLLVIEW_VIEWID);
+            NotSetApiKeysScrollView->SetTouchable(true);
+            NotSetApiKeysScrollView->SetDraggable(true);
+            if (dragListener == nullptr)
+            {
+                dragListener = new ApiKeysPresenter();
+                if (dragListener == nullptr)
+                {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::dragListener new fail!");
+                }
+            }
+            NotSetApiKeysScrollView->SetOnDragListener(dragListener);
+            /* -------------------------------------------------------------------------- */
+            NotSetApiKeysEnsureButton = new UIButton();
+            if (NotSetApiKeysEnsureButton == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::NotSetApiKeysEnsureButton new fail!");
+                return nullptr;
+            }
+            NotSetApiKeysEnsureButton->SetPosition(93, 340, 280, 90);
+            NotSetApiKeysEnsureButton->SetViewId(NOTSETAPIKEYS_ENSURE_BUTTON_VIEWID);
+            NotSetApiKeysEnsureButton->SetStyle(STYLE_BACKGROUND_COLOR, 0xfffd5213);
+            NotSetApiKeysEnsureButton->SetStyleForState(STYLE_BACKGROUND_COLOR, 0xff383838, UIButton::PRESSED);
+            if (clickListener == nullptr)
+            {
+                clickListener = new ApiKeysPresenter();
+                if (clickListener == nullptr)
+                {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "NotSetApiKeysView::clickListener new fail!");
+                }
+            }
+            NotSetApiKeysEnsureButton->SetOnClickListener(clickListener);
+            NotSetApiKeysScrollView->Add(NotSetApiKeysEnsureButton);
+            /* -------------------------------------------------------------------------- */
+            if (!CreateNotSetApiKeysViewLabel())
+            {
+                return nullptr;
+            }
+        }
+        return NotSetApiKeysScrollView;
+    }
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/SetApiKeysView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/apikeys/SetApiKeysView.cpp
new file mode 100644 (file)
index 0000000..6ba5687
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * @Author: luozheng 1732036298@qq.com
+ * @Date: 2024-07-29 16:04:23
+ * @LastEditors: luozheng 1732036298@qq.com
+ * @LastEditTime: 2024-11-05 11:20:35
+ * @FilePath: /xts_origin/FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/src/apikeys/SetApiKeysView.cpp
+ */
+
+#include "aivoice/include/apikeys/SetApiKeysView.h"
+#include "aivoice/include/apikeys/ApiKeysPresenter.h"
+#include "wearable_log.h"
+#include "ui_resource_string.h"
+namespace OHOS
+{
+    SetApiKeysView::SetApiKeysView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::SetApiKeysView");
+    }
+
+    SetApiKeysView::~SetApiKeysView()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::~SetApiKeysView");
+        ClearAll();
+    }
+
+    void SetApiKeysView::ClearAll(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::ClearAll");
+
+        if (SetApiKeysScrollView != nullptr)
+        {
+            SetApiKeysScrollView->RemoveAll();
+            if (clickListener != nullptr)
+            {
+                delete clickListener;
+                clickListener = nullptr;
+            }
+            if (dragListener != nullptr)
+            {
+                delete dragListener;
+                dragListener = nullptr;
+            }
+            if (SetApiKeysTitleLabel != nullptr)
+            {
+                delete SetApiKeysTitleLabel;
+                SetApiKeysTitleLabel = nullptr;
+            }
+            if (SetApiKeysImage != nullptr)
+            {
+                delete SetApiKeysImage;
+                SetApiKeysImage = nullptr;
+            }
+            if (SetApiKeysDeleteLabel != nullptr)
+            {
+                delete SetApiKeysDeleteLabel;
+                SetApiKeysDeleteLabel = nullptr;
+            }
+            if (SetApiKeysNoteLabel[0] != nullptr)
+            {
+                delete SetApiKeysNoteLabel[0];
+                SetApiKeysNoteLabel[0] = nullptr;
+            }
+            if (SetApiKeysNoteLabel[1] != nullptr)
+            {
+                delete SetApiKeysNoteLabel[1];
+                SetApiKeysNoteLabel[1] = nullptr;
+            }
+            if (SetApiKeysDeleteButton != nullptr)
+            {
+                delete SetApiKeysDeleteButton;
+                SetApiKeysDeleteButton = nullptr;
+            }
+            delete SetApiKeysScrollView;
+            SetApiKeysScrollView = nullptr;
+        }
+    }
+
+    UILabelExt *SetApiKeysView::SetApiKeysViewLabelInit(LabelConfig &labelconfig)
+    {
+        UILabelExt *label = new UILabelExt();
+        if (label == nullptr)
+        {
+            return nullptr;
+        }
+        label->SetPosition(labelconfig.left, labelconfig.top, labelconfig.width, labelconfig.height);
+        label->SetStyle(STYLE_TEXT_FONT, labelconfig.fontSize);
+        label->SetStyle(STYLE_LINE_HEIGHT, labelconfig.lineHeigh);
+        label->SetTextId(labelconfig.textId);
+        label->SetLineBreakMode(labelconfig.lineBreakMode);
+        label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        label->SetRollSpeed(23);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, labelconfig.fontSize);
+        return label;
+    }
+
+    bool SetApiKeysView::CreateSetApiKeysViewLabel(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::CreateSetApiKeysViewLabel");
+        LabelConfig labelConfig = {
+            .left = 83,
+            .top = 50,
+            .width = 300,
+            .height = 35,
+            .fontSize = 30,
+            .lineHeigh = 35,
+            .textId = STR_API_KEYS, /*API Keys*/
+            .lineBreakMode = UILabel::LINE_BREAK_OSCILLATION,
+        };
+        SetApiKeysTitleLabel = SetApiKeysViewLabelInit(labelConfig);
+        if (SetApiKeysTitleLabel == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::SetApiKeysTitleLabel new fail!");
+            return false;
+        }
+        SetApiKeysScrollView->Add(SetApiKeysTitleLabel);
+        /* -------------------------------------------------------------------------- */
+        int textId[] = {STR_KHBB, STR_GTAS};
+        for (int i = 0; i < static_cast<int>((sizeof(textId) / sizeof(textId[0]))); i++)
+        {
+            labelConfig.left = 53;
+            labelConfig.top = 235 + i * 35;
+            labelConfig.width = 360;
+            labelConfig.textId = textId[i];
+            SetApiKeysNoteLabel[i] = SetApiKeysViewLabelInit(labelConfig);
+            if (SetApiKeysNoteLabel[i] == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::SetApiKeysNoteLabel[%d] new fail!", i);
+                return false;
+            }
+            SetApiKeysScrollView->Add(SetApiKeysNoteLabel[i]);
+        }
+        /* -------------------------------------------------------------------------- */
+        labelConfig.left = 133;
+        labelConfig.top = 368;
+        labelConfig.width = 200;
+        labelConfig.textId = STR_DELETE; /*删除*/
+        SetApiKeysDeleteLabel = SetApiKeysViewLabelInit(labelConfig);
+        if (SetApiKeysDeleteLabel == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::SetApiKeysDeleteLabel new fail!");
+            return false;
+        }
+        SetApiKeysScrollView->Add(SetApiKeysDeleteLabel);
+        return true;
+    }
+
+    /*成功配置了API Keys视图*/
+    UIScrollView *SetApiKeysView::CreateSetApiKeysView(void)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::CreateSetApiKeysView");
+        if (SetApiKeysScrollView == nullptr)
+        {
+            SetApiKeysScrollView = new UIScrollView();
+            if (SetApiKeysScrollView == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::CreateSetApiKeysScrollView new fail!");
+                return nullptr;
+            }
+            SetApiKeysScrollView->SetPosition(0, 0, 466, 466);
+            SetApiKeysScrollView->SetViewId(SETAPIKEYS_SCROLLVIEW_VIEWID);
+            SetApiKeysScrollView->SetTouchable(true);
+            SetApiKeysScrollView->SetDraggable(true);
+            if (dragListener == nullptr)
+            {
+                dragListener = new ApiKeysPresenter();
+                if (dragListener == nullptr)
+                {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::dragListener new fail!");
+                }
+            }
+            SetApiKeysScrollView->SetOnDragListener(dragListener);
+            /* -------------------------------------------------------------------------- */
+            SetApiKeysImage = new UIImageView();
+            if (SetApiKeysImage == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::SetApiKeysImage new fail!");
+            }
+            SetApiKeysImage->SetPosition(193, 121, 80, 80);
+            SetApiKeysImage->SetSrc(SETAPIKEYS_IMAGE_PATH);
+            SetApiKeysScrollView->Add(SetApiKeysImage);
+            /* -------------------------------------------------------------------------- */
+            SetApiKeysDeleteButton = new UIButton();
+            if (SetApiKeysDeleteButton == nullptr)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::SetApiKeysDeleteButton new fail!");
+                return nullptr;
+            }
+            SetApiKeysDeleteButton->SetPosition(93, 340, 280, 90);
+            SetApiKeysDeleteButton->SetViewId(SETAPIKEYS_DELETE_BUTTON_VIEWID);
+            SetApiKeysDeleteButton->SetStyle(STYLE_BACKGROUND_COLOR, 0xfffd5213);
+            SetApiKeysDeleteButton->SetStyleForState(STYLE_BACKGROUND_COLOR, 0xff383838, UIButton::PRESSED);
+            if (clickListener == nullptr)
+            {
+                clickListener = new ApiKeysPresenter();
+                if (clickListener == nullptr)
+                {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetApiKeysView::clickListener new fail!");
+                }
+            }
+            SetApiKeysDeleteButton->SetOnClickListener(clickListener);
+            SetApiKeysScrollView->Add(SetApiKeysDeleteButton);
+            /* -------------------------------------------------------------------------- */
+            if (!CreateSetApiKeysViewLabel())
+            {
+                return nullptr;
+            }
+        }
+        return SetApiKeysScrollView;
+    }
+}
\ No newline at end of file