#include "TjdUiAppEbookPresenter.h" #include "NativeAbility.h" #include "TjdUiAppEbookAdapter.h" #include "TjdUiAppEbookModel.h" #include "TjdUiAppEbookView.h" #include "TjdUiImageIds.h" #include "common/image_cache_manager.h" #include "common/key_code.h" #include "dock/input_device.h" #include "fs_user_common.h" #include "graphic_service.h" #include "sys_config.h" #include "task_driver_event.h" #include #include "TjdUiRegisterManager.h" using namespace OHOS; #define ENABLE_PRINT_INFO 1 #define ENABLE_DEBUG 1 #if ENABLE_PRINT_INFO #define static_print_info(...) sys_ui_log_i(__VA_ARGS__) // 一般信息打印宏控制 #define static_print_warn(...) sys_ui_log_w(__VA_ARGS__) // 警告信息打印一般常开 #define static_print_error(...) sys_ui_log_e(__VA_ARGS__) // 错误信息打印一般常开 #if ENABLE_DEBUG #define static_print_debug(...) sys_ui_log_d(__VA_ARGS__) // 调试信息打印 #else #define static_print_debug(...) #endif #else #define static_print_info(...) #define static_print_warn(...) #define static_print_error(...) #define static_print_debug(...) #endif namespace TJD { TJD_REGIST_NATIVE_MENU(TJD_APP_VIEW_EBOOK, TjdUiAppEbookView, TjdUiAppEbookPresenter, IMG_MENU_LIST_MENU_BOOK, STR_ID_21); // clang-format off #define DRAG_EXIT_DISTANCE 170 #define PERLOAD_TEXT_NUM_PAGE 500 #define PERLOAD_CHAPTER_COUNT 1000 #define BOOK_JSON_PATH TJD_FS_DIR_BOOK"/booklist.json" #define BOOK_PATH TJD_FS_DIR_BOOK"/" // clang-format on static void *g_task_ui_ebook_handle; static TjdUiAppEbookPresenter *g_pv_UiAppEbookPresenter = nullptr; bool renameFile(const char *oldName, const char *newName) { return rename(oldName, newName) == 0; } // 检查字节为哪种utf-8字符头部 static uint8_t isUtf8StartByte(uint8_t byte) { if ((byte & 0x80) == 0) { return 1; // 0xxxxxxx } else if ((byte & 0xE0) == 0xC0) { return 2; // 110xxxxx } else if ((byte & 0xF0) == 0xE0) { return 3; // 1110xxxx } else if ((byte & 0xF8) == 0xF0) { return 4; // 11110xxx } return 0; // 不是UTF-8字符的头部 } EbookItem *FindItemFromListById(std::list &booklist, uint8_t id) { auto it = std::find_if(booklist.begin(), booklist.end(), [&](const EbookItem &s) { return s.id == id; }); if (it != booklist.end()) { return &(*it); } else { return nullptr; } } TjdUiAppEbookPresenter::TjdUiAppEbookPresenter() { static_print_info("TjdUiAppEbookPresenter::%s", __func__); g_pv_UiAppEbookPresenter = this; ImageCacheManager::GetInstance().LoadAllInMultiRes(BOOK_BIN_PATH); textBuffer_ = new TextBlockManager(); } TjdUiAppEbookPresenter::~TjdUiAppEbookPresenter() { static_print_info("TjdUiAppEbookPresenter::%s", __func__); g_pv_UiAppEbookPresenter = nullptr; ImageCacheManager::GetInstance().UnloadAllInMultiRes(BOOK_BIN_PATH); if (jumpTimerId_ != nullptr) { osTimerDelete(jumpTimerId_); jumpTimerId_ = nullptr; } if (textBuffer_ != nullptr) { delete textBuffer_; textBuffer_ = nullptr; } } TjdUiAppEbookPresenter *TjdUiAppEbookPresenter::GetInstance(void) { return g_pv_UiAppEbookPresenter; } void TjdUiAppEbookPresenter::OnStart() { static_print_info("TjdUiAppEbookPresenter::%s", __func__); TjdUiCommonOnKeyListener::GetInstance()->SetOnKeyActListener(this, KeyModelType::APP_KEY_TYPE); TjdUiAppEbookModel::GetInstance().LoadBooksFromJson(BOOK_JSON_PATH, bookList); uint8_t bookSize = bookList.size(); static_print_debug("bookSize: %d", bookSize); TjdUiAppEbookModel::GetInstance().ScanAndUpdateBooks(TJD_FS_DIR_BOOK, bookList); static_print_debug("bookList.size(): %d", bookList.size()); if (bookSize != bookList.size()) { TjdUiAppEbookModel::GetInstance().SaveBooksToJson(BOOK_JSON_PATH, bookList); } for (auto it = bookList.begin(); it != bookList.end(); it++) { static_print_debug("bookList id:%d name:%s", it->id, (it->name).c_str()); } } void TjdUiAppEbookPresenter::OnResume() { static_print_info("TjdUiAppEbookPresenter::%s", __func__); if (!ebook_slice_inited) { ebook_slice_inited = true; view_->UpdateEbookAdapter(bookList); if (view_->GetAdapter()->GetList().size() == 0) { view_->ShowNoneView(currentView); } else { view_->GetEbookUIList()->SetAdapter(view_->GetEbookAdapter()); view_->GetEbookUIList()->ScrollBy((VERTICAL_RESOLUTION - EBOOK_ITEM_H) / 2); } } Presenter::OnResume(); } void TjdUiAppEbookPresenter::OnPause() { static_print_info("TjdUiAppEbookPresenter::%s", __func__); Presenter::OnPause(); } void TjdUiAppEbookPresenter::OnStop() { static_print_info("TjdUiAppEbookPresenter::%s", __func__); TjdUiCommonOnKeyListener::GetInstance()->ClearOnKeyActListener(KeyModelType::APP_KEY_TYPE); } bool TjdUiAppEbookPresenter::OnClick(OHOS::UIView &view, const OHOS::ClickEvent &event) { static_print_info("TjdUiAppEbookPresenter::%s", __func__); if (&view == view_->cancelButton || &view == view_->setConfirmButton) { ExitCurrentView(); return true; } else if (&view == view_->confirmButton) { view_->DeleteEbookItemFromList(selectedItem.id); ExitCurrentView(); return true; } else if (&view == view_->setButton) { view_->ShowSettingView(currentView); return true; } else if (&view == view_->nextButton) { FillTextToTextLabel(NEXT_PAGE); } else if (&view == view_->lastButton) { FillTextToTextLabel(LAST_PAGE); } return false; } bool TjdUiAppEbookPresenter::OnKeyAct(OHOS::UIView &view, const OHOS::KeyEvent &event) { if (!TjdUiCommonOnKeyListener::GetInstance()->CheckIsExitEvent(event)) { return true; } ExitCurrentView(); return false; } void TjdUiAppEbookPresenter::OnItemSelected(int16_t index, OHOS::UIView *view) { static_print_info("TjdUiAppEbookPresenter::%s index:%d", __func__, index); if (view != nullptr) { itemViewSele = static_cast(view); itemViewSele->SelectedChange(); if (preItemViewSele != nullptr && preItemViewSele != itemViewSele) { preItemViewSele->Reset(); } preItemViewSele = itemViewSele; } } void TjdUiAppEbookPresenter::OnScrollStart(int16_t index, UIView *view) { auto ebookView = TjdUiAppEbookView::GetInstance(); if (ebookView == nullptr) { return; } ebookView->SetTitleVisible(false); } void TjdUiAppEbookPresenter::OnScrollEnd(int16_t index, UIView *view) { auto ebookView = TjdUiAppEbookView::GetInstance(); if (ebookView == nullptr) { return; } if (ebookView->GetListPosition() >= 50) { ebookView->SetTitleVisible(true); } else { ebookView->SetTitleVisible(false); } } void TjdUiAppEbookPresenter::ClickEBookAdapterCallback(OHOS::UIView *view, EbookItem item) { selectedItem = item; if (view->GetViewType() == UIViewType::UI_VIEW_GROUP) { std::string str = BOOK_PATH + std::string(selectedItem.name) + ".txt"; static_print_info("OnClick item_.id:%d item_.name:%s", selectedItem.id, selectedItem.name.c_str()); textBuffer_->OpenFile(str.c_str()); PreLoadBook(); } else if (view->GetViewType() == UIViewType::UI_LABEL_BUTTON) { view_->ShowDeleteView(currentView); } } void TjdUiAppEbookPresenter::FillTextToTextLabel(EbookPageType page) { uint16_t pos; std::string displayStr, subStr; if (!textBuffer_->FileIsOpen()) { static_print_error("FillTextToTextLabel:: file is not open!"); return; } if (page == LAST_PAGE) { if (curPage_ < 2) { static_print_info("FillTextToTextLabel:: this is the first page"); return; } view_->nextViewText->SetText(view_->curViewText->GetText()); view_->curViewText->SetText(view_->lastViewText->GetText()); curPage_--; if (curPage_ == 1) { view_->lastViewText->SetText(nullptr); return; } uint32_t startPos = pageWordCounts_.at(curPage_ - 2); textBuffer_->readFromFile(startPos); subStr = textBuffer_->GetBuffer().substr(0, PERLOAD_TEXT_NUM_PAGE); view_->lastViewText->SetText(subStr.c_str()); pos = view_->lastViewText->GetTruncateIndex(); displayStr = subStr.substr(0, pos); view_->lastViewText->SetText(displayStr.c_str()); bufLastPos_ = startPos + displayStr.size(); static_print_debug("bufLastPos_:%d displayStr size: %d", bufLastPos_, displayStr.size()); // printf("%s\n",displayStr.c_str()); } else if (page == NEXT_PAGE) { if (curPage_ >= pageWordCounts_.size()) { static_print_info("FillTextToTextLabel:: this is the end of page"); return; } view_->lastViewText->SetText(view_->curViewText->GetText()); view_->curViewText->SetText(view_->nextViewText->GetText()); curPage_++; if (pageWordCounts_.size() == curPage_) { view_->nextViewText->SetText(nullptr); return; } uint32_t startPos = pageWordCounts_[curPage_]; textBuffer_->readFromFile(startPos); subStr = textBuffer_->GetBuffer().substr(0, PERLOAD_TEXT_NUM_PAGE); view_->nextViewText->SetText(subStr.c_str()); pos = view_->nextViewText->GetTruncateIndex(); displayStr = subStr.substr(0, pos); view_->nextViewText->SetText(displayStr.c_str()); bufNextPos_ = startPos + displayStr.size(); static_print_debug("bufNextPos_:%d displayStr size: %d", bufNextPos_, displayStr.size()); // printf("%s\n",displayStr.c_str()); } } void TjdUiAppEbookPresenter::PreLoadBook() { view_->ShowMainView(currentView); view_->setWaitAnimator_->ShowView(); StartJumpTimer(); startThread(); } void TjdUiAppEbookPresenter::UnLoadBook() { textBuffer_->CloseFile(); FindItemFromListById(bookList, selectedItem.id)->curPage = curPage_; TjdUiAppEbookModel::GetInstance().SaveItemBookToJson(BOOK_JSON_PATH, *FindItemFromListById(bookList, selectedItem.id)); curPage_ = 0; pageWordCounts_.clear(); isLoadComplite = false; } void TjdUiAppEbookPresenter::startThread() { // if (selectedItem.) osThreadAttr_t task_attr = {"tjd_t_ui_ebook_load_book", 0, NULL, 0, NULL, 0x1c00, (osPriority_t)(16), 0, 0}; g_task_ui_ebook_handle = osThreadNew(LoadBookTask, this, &task_attr); osThreadDetach(g_task_ui_ebook_handle); } // void TjdUiAppEbookPresenter::LoadBookTask(void *arg) // { // TjdUiAppEbookPresenter *presenter = static_cast(arg); // static_print_info("LoadBook thread run"); // EbookItem *selectedItem = FindItemFromListById(presenter->bookList, presenter->selectedItem.id); // uint16_t pos = 0; // uint32_t preLoadPos = 0; // std::string subStr; // vector wordPerPageVec; // if (!selectedItem->loadOver) { // while (!selectedItem->loadOver && wordPerPageVec.size() <= PERLOAD_CHAPTER_COUNT) { // presenter->textBuffer_->readFromFile(preLoadPos); // subStr = presenter->textBuffer_->GetBuffer().substr(0, PERLOAD_TEXT_NUM_PAGE); // presenter->view_->nextViewText->SetText(subStr.c_str()); // pos = presenter->view_->nextViewText->GetTruncateIndex(); // wordPerPageVec.push_back(preLoadPos); // if (wordPerPageVec.size() >= 10) { // std::string str = selectedItem->name; // TjdUiAppEbookModel::GetInstance().WriteEbookSizesToBinFile(str, wordPerPageVec, TJD_FS_DIR_BOOK); // wordPerPageVec.clear(); // } // if (pos == Text::TEXT_ELLIPSIS_END_INV) { // selectedItem->loadOver = true; // break; // } // preLoadPos += pos; // } // std::string str = selectedItem->name; // TjdUiAppEbookModel::GetInstance().WriteEbookSizesToBinFile(str, wordPerPageVec, TJD_FS_DIR_BOOK); // wordPerPageVec.clear(); // } // presenter->isLoadComplite = true; // } void TjdUiAppEbookPresenter::LoadBookTask(void *arg) { TjdUiAppEbookPresenter *presenter = static_cast(arg); static_print_info("LoadBook thread run"); EbookItem *selectedItem = FindItemFromListById(presenter->bookList, presenter->selectedItem.id); uint16_t pos = 0; uint32_t preLoadPos = 0; std::string subStr; vector wordPerPageVec; if (!selectedItem->loadOver) { while (!selectedItem->loadOver) { presenter->textBuffer_->readFromFile(preLoadPos); subStr = presenter->textBuffer_->GetBuffer().substr(0, PERLOAD_TEXT_NUM_PAGE); presenter->view_->nextViewText->SetText(subStr.c_str()); pos = presenter->view_->nextViewText->GetTruncateIndex(); wordPerPageVec.push_back(preLoadPos); if (wordPerPageVec.size() >= 10) { std::string str = selectedItem->name; TjdUiAppEbookModel::GetInstance().WriteEbookSizesToBinFile(str, wordPerPageVec, TJD_FS_DIR_BOOK); wordPerPageVec.clear(); } if (pos == Text::TEXT_ELLIPSIS_END_INV) { selectedItem->loadOver = true; break; } preLoadPos += pos; } std::string str = selectedItem->name; TjdUiAppEbookModel::GetInstance().WriteEbookSizesToBinFile(str, wordPerPageVec, TJD_FS_DIR_BOOK); wordPerPageVec.clear(); } presenter->isLoadComplite = true; } void TjdUiAppEbookPresenter::StartJumpTimer() { if (jumpTimerId_ == nullptr) { jumpTimerId_ = osTimerNew( [](void *arg) { if (TjdUiAppEbookPresenter::GetInstance()->isLoadComplite) { TjdUiAppEbookPresenter::GetInstance()->StopJumpTimer(); GraphicService::GetInstance()->PostGraphicEvent( std::bind(JumpTimerCallback, TjdUiAppEbookPresenter::GetInstance())); return; } }, osTimerPeriodic, nullptr, nullptr); if (jumpTimerId_ == nullptr) { return; } } int32_t ret = osTimerStart(jumpTimerId_, 100); if (ret != 0) { static_print_error("[%s] osTimerStart fail.", __func__); return; } } void TjdUiAppEbookPresenter::StopJumpTimer() { if (jumpTimerId_ == nullptr) { return; } int32_t ret = osTimerStop(jumpTimerId_); if (ret != 0) { static_print_error("TjdUiAppEbookPresenter::ResetHideVolumeBarTimer timer fail"); return; } } void TjdUiAppEbookPresenter::WaitAnimatorCallback() { uint16_t pos = 0; uint32_t startPos = 0; std::string displayStr, subStr; curPage_ = FindItemFromListById(bookList, selectedItem.id)->curPage; std::string str = FindItemFromListById(bookList, selectedItem.id)->name; pageWordCounts_ = TjdUiAppEbookModel::GetInstance().ReadEbookSizesFromBinFile(str, TJD_FS_DIR_BOOK, 0, 1000); static_print_info("ReadEbookSizesFromBinFile: counts size:%d", pageWordCounts_.size()); // for (auto it : pageWordCounts_) { // static_print_debug("%d ", it); // } if (pageWordCounts_.size() < curPage_) { static_print_info("pageWordCounts_.size() < curPage_"); return; } startPos = pageWordCounts_[curPage_ - 1]; textBuffer_->readFromFile(startPos); subStr = textBuffer_->GetBuffer().substr(0, PERLOAD_TEXT_NUM_PAGE); view_->curViewText->SetText(subStr.c_str()); pos = view_->curViewText->GetTruncateIndex(); displayStr = subStr.substr(0, pos); view_->curViewText->SetText(displayStr.c_str()); if (pageWordCounts_.size() < curPage_ + 1) { static_print_info("pageWordCounts_.size() < curPage_+1"); return; } startPos = pageWordCounts_[curPage_]; textBuffer_->readFromFile(startPos); subStr = textBuffer_->GetBuffer().substr(0, PERLOAD_TEXT_NUM_PAGE); view_->nextViewText->SetText(subStr.c_str()); pos = view_->nextViewText->GetTruncateIndex(); displayStr = subStr.substr(0, pos); view_->nextViewText->SetText(displayStr.c_str()); } void TjdUiAppEbookPresenter::JumpTimerCallback(void *param) { TjdUiAppEbookPresenter *persenter = static_cast(param); TjdUiAppEbookPresenter::GetInstance()->WaitAnimatorCallback(); static_print_info("WaitAnimatorCallback over"); TjdUiAppEbookView::GetInstance()->setWaitAnimator_->HideView(); static_print_info("HideView over"); } void TjdUiAppEbookPresenter::DeleteBookListItem(uint32_t id) { auto it = std::find_if(bookList.begin(), bookList.end(), [id](const EbookItem &item) { return item.id == id; }); if (it != bookList.end()) { bookList.erase(it); } } void TjdUiAppEbookPresenter::ExitEbookSlice(void) { static_print_info("TjdUiAppEbookPresenter::%s", __func__); OHOS::NativeAbility::GetInstance().ChangePreSlice(); } void TjdUiAppEbookPresenter::ExitCurrentView(void) { static_print_info("TjdUiAppEbookPresenter::%s", __func__); // 判断当前处于几级页面并返回,若在顶层则退出 if (view_->viewHierarchy.find(currentView) != view_->viewHierarchy.end()) { if (currentView == EBOOK_MAIN_VIEW) { UnLoadBook(); } view_->ChangeView(view_->viewHierarchy.at(currentView), currentView); } else { printf("currentView = %d not in viewHierarchy\n", currentView); ExitEbookSlice(); } } /*----------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------*/ /*-------------------------------- Class TextBlockManager --------------------------------*/ /*----------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------*/ // 辅助函数:从文件读取数据到缓冲区 uint32_t TextBlockManager::readIntoBuffer(std::vector &buffer, size_t numBytes, std::streampos offset) { file_.clear(); // 清除之前的错误状态 file_.seekg(offset, std::ios::beg); buffer.resize(numBytes); file_.read(buffer.data(), numBytes); // 如果读取的字节数少于请求的字节数,可能是到达了文件末尾 if (file_.gcount() < numBytes) { buffer.resize(file_.gcount()); } return buffer.size(); } bool TextBlockManager::OpenFile(const char *filename) { file_.open(filename, std::ios::binary); if (!file_.is_open()) { static_print_error("Failed to open file: %s", filename); return false; } buffer_.resize(blockSize); return true; } void TextBlockManager::CloseFile() { buffer_.clear(); file_.close(); } // 从当前seek位置读取数据到缓冲区 bool TextBlockManager::readFromFile(size_t pos) { buffer_.resize(blockSize); size_t size = readIntoBuffer(buffer_, buffer_.size(), pos); static_print_info("%s:: start_pos: %d size: %d", __func__, pos, size); return true; } std::string TextBlockManager::GetBuffer() { std::string result(buffer_.begin(), buffer_.begin() + buffer_.size()); return result; } } // namespace TJD