mcu_hi3321_watch/tjd/ui/app/e-book/TjdUiAppEbookPresenter.cpp
2025-05-26 20:15:20 +08:00

576 lines
20 KiB
C++

#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 <iostream>
#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<EbookItem> &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<TjdUiAppEbookView>::OnResume();
}
void TjdUiAppEbookPresenter::OnPause()
{
static_print_info("TjdUiAppEbookPresenter::%s", __func__);
Presenter<TjdUiAppEbookView>::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<TjdEbookItemView *>(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<TjdUiAppEbookPresenter *>(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<uint32_t> 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<TjdUiAppEbookPresenter *>(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<uint32_t> 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<TjdUiAppEbookPresenter *>(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<char> &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