96b553d7创建于 2025年12月23日历史提交
/*

# Copyright (c) 2025 Huawei Device Co., Ltd.

# Licensed under the Apache License, Version 2.0 (the "License");

# you may not use this file except in compliance with the License.

# You may obtain a copy of the License at

#

#     http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS,

# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

# See the License for the specific language governing permissions and

# limitations under the License.

*/



#include "dialog_wrapper.h"

#include "libvlc_wrapper.h"

#include "ohos_log.h"

#include <map>



napi_value DialogWrapper::DialogWrapperConstructor(napi_env env, napi_callback_info info)

{

    napi_value arkTSDialog = nullptr;

    napi_get_cb_info(env, info, nullptr, nullptr, &arkTSDialog, nullptr);

    return arkTSDialog;

}



napi_value DialogWrapper::QuestionDialogConstructor(napi_env env, napi_callback_info info)

{

    napi_value arkTSDialog = nullptr;

    napi_get_cb_info(env, info, nullptr, nullptr, &arkTSDialog, nullptr);

    return arkTSDialog;

}



struct DialogCallbackCtx {

    std::string title;

    std::string text;

    libvlc_dialog_question_type type;

    std::string cancel;

    std::string action1;

    std::string action2;

};



void DialogWrapper::InitCallback(napi_env env, napi_value cb)

{

    struct CallbackConfig {

        const char* propertyName;

        const char* resourceName;

        napi_threadsafe_function* targetFn;

        napi_threadsafe_function_call_js callJs;

    };



    napi_threadsafe_function* functions[] = {

        &DialogWrapper::pfDisplayErrorFn_,

        &DialogWrapper::pfDisplayLoginFn_,

        &DialogWrapper::pfDisplayProgressFn_,

        &DialogWrapper::pfCancelFn_,

        &DialogWrapper::pfUpdateProgressFn_,

        &DialogWrapper::pfDisplayQuestionFn_

    };

    

    for (auto fn : functions) {

        if (*fn != nullptr) {

            napi_release_threadsafe_function(*fn, napi_tsfn_abort);

            *fn = nullptr;

        }

    }



    CallbackConfig configs[] = {

        {"onQuestion", "pfQuestionFn", &DialogWrapper::pfDisplayQuestionFn_, DisplayQuestionCompleteWork},

        {"onError", "pfErrorFn", &DialogWrapper::pfDisplayErrorFn_, DisplayErrorCompleteWork},

        {"onLogin", "pfLoginFn", &DialogWrapper::pfDisplayLoginFn_, DisplayLoginCompleteWork},

        {"onProgress", "pfProgressFn", &DialogWrapper::pfDisplayProgressFn_, DisplayProgressCompleteWork},

        {"onCanceled", "pfCancelFn", &DialogWrapper::pfCancelFn_, CancelCompleteWork},

        {"onProgressUpdate", "pfUpdateProgressFn", &DialogWrapper::pfUpdateProgressFn_, UpdateProgressCompleteWork},

    };



    for (const auto& config : configs) {

        napi_value callbackFun = nullptr;

        napi_get_named_property(env, cb, config.propertyName, &callbackFun);

        

        if (callbackFun == nullptr) {

            return;

        }



        napi_value resourceName;

        napi_create_string_utf8(env, config.resourceName, NAPI_AUTO_LENGTH, &resourceName);

        napi_create_threadsafe_function(env, callbackFun, nullptr, resourceName,

            0,

            1,

            nullptr,

            [](napi_env env, void* finalize_data, void* finalize_hint) {},

            nullptr,

            config.callJs,

            config.targetFn);

    }

}



static const libvlc_dialog_cbs dialog_cbs = {

    .pf_display_login = DialogWrapper::DisplayLogin,

    .pf_display_question = DialogWrapper::DisplayQuestion,

    .pf_display_progress = DialogWrapper::DisplayProgress,

    .pf_cancel = DialogWrapper::Cancel,

    .pf_update_progress = DialogWrapper::UpdateProgress,

};



napi_value DialogWrapper::SetCallbacks(napi_env env, napi_callback_info info)

{

    LOGE();

    napi_value arkTSDialog = nullptr;

    size_t argc = 2;

    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, &arkTSDialog, nullptr);

    

    LibVLCWrapper *vlc = nullptr;

    napi_status status = napi_unwrap(env, args[0], reinterpret_cast<void **>(&vlc));

    if (status != napi_ok) {

        LOGE("unwrap failed");

        return nullptr;

    }

    

    InitCallback(env, args[1]);



    libvlc_dialog_set_callbacks(vlc->instance_, &dialog_cbs, nullptr);

    LOGE();

    return nullptr;

}



napi_value DialogWrapper::PostAction(napi_env env, napi_callback_info info)

{

    napi_value arkTSDialog = nullptr;

    size_t argc = 1;

    napi_value args[1] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, &arkTSDialog, nullptr);

    libvlc_dialog_id *id = nullptr;

    napi_status status = napi_unwrap(env, arkTSDialog, reinterpret_cast<void **>(&id));

    if (status != napi_ok) {

        LOGE("unwrap DialogWrapper failed!");

        return nullptr;

    }

    LOGE("PostAction dialogId: %p", id);

    int32_t action = 0;

    napi_get_value_int32(env, args[0], &action);

    int ret = libvlc_dialog_post_action(id, action);

    napi_value arkRet = 0;

    napi_create_uint32(env, ret, &arkRet);

    return arkRet;

}



napi_value DialogWrapper::Dismiss(napi_env env, napi_callback_info info)

{

    napi_value arkTSDialog = nullptr;

    napi_get_cb_info(env, info, nullptr, nullptr, &arkTSDialog, nullptr);

    libvlc_dialog_id *id = nullptr;

    napi_status status = napi_unwrap(env, arkTSDialog, reinterpret_cast<void **>(&id));

    if (status != napi_ok) {

        LOGE("unwrap DialogWrapper failed!");

        return nullptr;

    }



    int ret = libvlc_dialog_dismiss(id);

    napi_value arkRet = 0;

    napi_create_uint32(env, ret, &arkRet);

    return arkRet;

}



void DialogWrapper::DisplayQuestion(void *pData, libvlc_dialog_id *pId,

                                    const char *title, const char *text,

                                    libvlc_dialog_question_type type,

                                    const char *cancel, const char *action1,

                                    const char *action2)

{

    auto* data = new QuestionData {

        pId,

        SafeString(title),

        SafeString(text),

        type,

        SafeString(cancel),

        SafeString(action1),

        SafeString(action2),

    };

    napi_call_threadsafe_function(DialogWrapper::pfDisplayQuestionFn_, data, napi_tsfn_blocking);

}



void DialogWrapper::DisplayError(void *pData, const char *title, const char *text)

{

    DialogWrapper* wrapper = static_cast<DialogWrapper*>(pData);

    if (!wrapper || !wrapper->pfDisplayErrorFn_) {

        return;

    }

    auto* data = new ErrorData{

        SafeString(title),

        SafeString(text),

    };



    napi_call_threadsafe_function(wrapper->pfDisplayErrorFn_, data, napi_tsfn_blocking);

}



void DialogWrapper::DisplayLogin(void *pData, libvlc_dialog_id *pId,

                                 const char *title, const char *text,

                                 const char *defaultUsername,

                                 bool askStore)

{

    auto* data = new LoginData{

        pId,

        SafeString(title),

        SafeString(text),

        SafeString(defaultUsername),

        askStore,

    };



    napi_call_threadsafe_function(DialogWrapper::pfDisplayLoginFn_, data, napi_tsfn_blocking);

}



void DialogWrapper::DisplayProgress(void *pData, libvlc_dialog_id *pId,

                                    const char *title, const char *text,

                                    bool indeterminate, float position,

                                    const char *cancel)

{

    DialogWrapper* wrapper = static_cast<DialogWrapper*>(pData);

    if (!wrapper || !wrapper->pfDisplayProgressFn_) {

        return;

    }



    auto* data = new ProgressData{

        pId,

        SafeString(title),

        SafeString(text),

        indeterminate,

        position,

        SafeString(cancel),

    };



    napi_call_threadsafe_function(wrapper->pfDisplayProgressFn_, data, napi_tsfn_blocking);

}



void DialogWrapper::Cancel(void *pData, libvlc_dialog_id *pId)

{

    DialogWrapper* wrapper = static_cast<DialogWrapper*>(pData);

    if (!wrapper || !wrapper->pfCancelFn_) {

        return;

    }



    auto* data = new CancelData{

        pId,

    };



    napi_call_threadsafe_function(wrapper->pfCancelFn_, data, napi_tsfn_blocking);

}



void DialogWrapper::UpdateProgress(void *pData, libvlc_dialog_id *pId,

                                   float position, const char *text)

{

    DialogWrapper* wrapper = static_cast<DialogWrapper*>(pData);

    if (!wrapper || !wrapper->pfUpdateProgressFn_) {

        return;

    }



    auto* data = new UpdateProgressData{

        pId,

        position,

        text,

    };



    napi_call_threadsafe_function(wrapper->pfUpdateProgressFn_, data, napi_tsfn_blocking);

}



void DialogWrapper::DisplayErrorCompleteWork(napi_env env, napi_value callback, void* context, void* data)

{

}



void DialogWrapper::DisplayLoginCompleteWork(napi_env env, napi_value callback, void* context, void* data)

{

}



void DialogWrapper::DisplayProgressCompleteWork(napi_env env, napi_value callback, void* context, void* data)

{

}



void DialogWrapper::CancelCompleteWork(napi_env env, napi_value callback, void* context, void* data)

{

}



void DialogWrapper::UpdateProgressCompleteWork(napi_env env, napi_value callback, void* context, void* data)

{

}



void DialogWrapper::DisplayQuestionCompleteWork(napi_env env, napi_value callback, void* context, void* data)

{

    if (!data) {

        return;

    }

    std::unique_ptr<QuestionData> errorData(static_cast<QuestionData*>(data));

    

    napi_value global;

    napi_get_global(env, &global);

    napi_value questionDialogClass = nullptr;

    napi_get_named_property(env, global, "QuestionDialog", &questionDialogClass);

    if (questionDialogClass == nullptr) {

        return;

    }

    napi_value instance;

    napi_new_instance(env, questionDialogClass, 0, nullptr, &instance);

    napi_wrap(env, instance, errorData->dialogId, [](napi_env env, void* data, void* hint) {}, nullptr, nullptr);

    

    napi_value tsData;

    napi_create_string_utf8(env, errorData->title.c_str(), NAPI_AUTO_LENGTH, &tsData);

    napi_set_named_property(env, instance, "title", tsData);

    napi_create_string_utf8(env, errorData->text.c_str(), NAPI_AUTO_LENGTH, &tsData);

    napi_set_named_property(env, instance, "text", tsData);

    napi_create_int32(env, errorData->type, &tsData);

    napi_set_named_property(env, instance, "type", tsData);

    napi_create_string_utf8(env, errorData->cancelText.c_str(), NAPI_AUTO_LENGTH, &tsData);

    napi_set_named_property(env, instance, "cancel", tsData);

    napi_create_string_utf8(env, errorData->action1.c_str(), NAPI_AUTO_LENGTH, &tsData);

    napi_set_named_property(env, instance, "action1", tsData);

    napi_create_string_utf8(env, errorData->action2.c_str(), NAPI_AUTO_LENGTH, &tsData);

    napi_set_named_property(env, instance, "action2", tsData);

    napi_call_function(env, instance, callback, 1, &instance, nullptr);

}



std::string DialogWrapper::SafeString(const char* str)

{

    return str ? std::string(str) : std::string();

}





static void CreateEnum(napi_env env, napi_value exports)

{

    napi_value eventEnum;

    napi_create_object(env, &eventEnum);

    std::map<std::string, libvlc_dialog_question_type> states = {

        {"LIBVLC_DIALOG_QUESTION_NORMAL", LIBVLC_DIALOG_QUESTION_NORMAL},

        {"LIBVLC_DIALOG_QUESTION_WARNING", LIBVLC_DIALOG_QUESTION_WARNING},

        {"LIBVLC_DIALOG_QUESTION_CRITICAL", LIBVLC_DIALOG_QUESTION_CRITICAL},

    };



    for (const auto& [k, v] : states) {

        napi_value num = nullptr;

        napi_create_int32(env, v, &num);

        napi_set_named_property(env, eventEnum, k.c_str(), num);

    }

    napi_set_named_property(env, exports, "libvlc_dialog_question_type", eventEnum);

}



napi_value DialogWrapper::Export(napi_env env, napi_value exports)

{

    napi_value dialog_class;

    napi_property_descriptor dialog_props[] = {

        { "setCallbacks", nullptr, SetCallbacks, nullptr, nullptr, nullptr, napi_static, nullptr }

    };

    

    napi_define_class(env, "Dialog", NAPI_AUTO_LENGTH,

                      [](napi_env env, napi_callback_info info) -> napi_value {

                          napi_value jsthis;

                          napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr);

                          return jsthis;

                      },

                      nullptr, 1, dialog_props, &dialog_class);

    napi_set_named_property(env, exports, "Dialog", dialog_class);

    

    napi_value global;

    napi_get_global(env, &global);

    napi_property_descriptor questionDialogProp[] = {

        {"postAction", nullptr, DialogWrapper::PostAction, nullptr, nullptr, nullptr, napi_default, nullptr},

        {"dismiss", nullptr, DialogWrapper::Dismiss, nullptr, nullptr, nullptr, napi_default, nullptr},

    };

    napi_value arkTSQuestionDialog = nullptr;

    const char *arkTSQuestionDialogName = "QuestionDialog";

    napi_define_class(env, arkTSQuestionDialogName, NAPI_AUTO_LENGTH, DialogWrapper::QuestionDialogConstructor, nullptr,

                      sizeof(questionDialogProp) / sizeof(questionDialogProp[0]),

                      questionDialogProp, &arkTSQuestionDialog);

    napi_set_named_property(env, global, arkTSQuestionDialogName, arkTSQuestionDialog);



    CreateEnum(env, exports);

    return exports;

}