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

367 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "TjdUiAppEbookModel.h"
#include "TjdUiAppEbookPresenter.h"
#include "cJSON.h"
#include "fs_user_common.h"
#include "sys_config.h"
#include <dirent.h>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.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_PRINT_INFO
#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(...)
#endif
namespace TJD {
// 辅助函数从cJSON对象中获取字符串字段
const char *get_cjson_string(cJSON *object, const char *key)
{
cJSON *value = cJSON_GetObjectItemCaseSensitive(object, key);
if (value != NULL && cJSON_IsString(value)) {
return value->valuestring;
}
return NULL;
}
// 辅助函数在cJSON数组中查找具有指定ID的对象
cJSON *find_book_by_id(cJSON *array, int id)
{
int arraySize = cJSON_GetArraySize(array);
for (int i = 0; i < arraySize; i++) {
cJSON *book = cJSON_GetArrayItem(array, i);
if (cJSON_IsObject(book) && cJSON_HasObjectItem(book, "id")) {
int book_id = cJSON_GetObjectItemCaseSensitive(book, "id")->valueint;
if (book_id == id) {
return book;
}
}
}
return NULL;
}
// 辅助函数从cJSON数组中删除具有指定ID的对象并删除对应文件
void delete_and_renumber_books(cJSON **books, int id_to_delete)
{
cJSON *new_array = cJSON_CreateArray();
int new_id = 0;
cJSON *book;
cJSON_ArrayForEach(book, *books)
{
int book_id = cJSON_GetObjectItemCaseSensitive(book, "id")->valueint;
if (book_id == id_to_delete) {
const char *book_name = cJSON_GetObjectItemCaseSensitive(book, "name")->valuestring;
if (book_name) {
std::string path = TJD_FS_DIR_BOOK + std::string("/");
std::string file_path = path + std::string(book_name) + ".txt";
static_print_info("delete file:%s", file_path.c_str());
int ret;
if ((ret = std::remove(file_path.c_str())) != 0) {
static_print_error("file delete fail: %d", ret);
return;
}
std::string file_bin_path = path + std::string(book_name) + ".bin";
if ((ret = std::remove(file_bin_path.c_str())) != 0) {
static_print_error("file delete fail: %d", ret);
}
}
continue; // 跳过当前循环迭代,不添加这本书到新数组中
}
// 更新ID并添加到新数组中
cJSON_DeleteItemFromObject(book, "id");
cJSON_AddItemToObject(book, "id", cJSON_CreateNumber(new_id++));
cJSON_AddItemToArray(new_array, cJSON_Duplicate(book, 1));
}
// 用新数组替换旧数组
cJSON_Delete(*books);
*books = new_array;
}
// 写入页数到bin文件
void TjdUiAppEbookModel::WriteEbookSizesToBinFile(std::string name, const std::vector<uint32_t> &sizes,
const char *path)
{
std::string filename = path;
filename += "/" + name + ".bin";
std::ofstream file(filename, std::ios::out | std::ios::binary | std::ios::app);
if (!file.is_open()) {
static_print_error("Failed to open file for writing");
return;
}
for (const auto &size : sizes) {
file.write(reinterpret_cast<const char *>(&size), sizeof(size));
}
file.close();
}
// 加载页数buf从bin文件
std::vector<uint32_t> TjdUiAppEbookModel::ReadEbookSizesFromBinFile(std::string name, const char *path,
size_t startElement, size_t count)
{
std::string filename = path;
filename += "/" + name + ".bin";
std::ifstream file(filename, std::ios::in | std::ios::binary);
if (!file.is_open()) {
static_print_error("Failed to open file for reading");
return {};
}
// 定位到起始位置
file.seekg(startElement * sizeof(uint32_t), std::ios::beg);
std::vector<uint32_t> readSizes;
uint32_t tempSize;
while (count-- > 0 && file.read(reinterpret_cast<char *>(&tempSize), sizeof(tempSize))) {
readSizes.push_back(tempSize);
}
file.close();
return readSizes;
}
// 加载书籍列表从 JSON 文件
bool TjdUiAppEbookModel::LoadBooksFromJson(const char *filename, std::list<EbookItem> &books)
{
std::ifstream file(filename);
std::stringstream buffer;
buffer << file.rdbuf();
std::string json_string = buffer.str();
cJSON *json = cJSON_Parse(json_string.c_str());
if (!json || !cJSON_IsArray(json)) {
static_print_error("Error parsing JSON");
return false;
}
cJSON *item;
cJSON_ArrayForEach(item, json)
{
cJSON *id_json = cJSON_GetObjectItemCaseSensitive(item, "id");
cJSON *name_json = cJSON_GetObjectItemCaseSensitive(item, "name");
cJSON *curChapter_json = cJSON_GetObjectItemCaseSensitive(item, "curChapter");
cJSON *curPage_json = cJSON_GetObjectItemCaseSensitive(item, "curPage");
cJSON *loadOver_json = cJSON_GetObjectItemCaseSensitive(item, "loadOver");
if (cJSON_IsNumber(id_json) && cJSON_IsString(name_json) && cJSON_IsNumber(curChapter_json) &&
cJSON_IsNumber(curPage_json) && cJSON_IsBool(loadOver_json)) {
books.emplace_back(static_cast<uint8_t>(id_json->valueint), name_json->valuestring,
static_cast<uint32_t>(curChapter_json->valueint),
static_cast<uint32_t>(curPage_json->valueint),
static_cast<bool>(loadOver_json->valueint));
}
}
cJSON_Delete(json);
return true;
}
// 将书籍列表保存到 JSON 文件
void TjdUiAppEbookModel::SaveBooksToJson(const char *filename, const std::list<EbookItem> &books)
{
cJSON *json = cJSON_CreateArray();
for (const auto &book : books) {
static_print_debug("book.id:%02d book.name:%s", book.id, book.name.c_str());
cJSON *book_json = cJSON_CreateObject();
cJSON_AddItemToObject(book_json, "id", cJSON_CreateNumber(book.id));
cJSON_AddItemToObject(book_json, "name", cJSON_CreateString(book.name.c_str()));
cJSON_AddItemToObject(book_json, "curChapter", cJSON_CreateNumber(book.curChapter));
cJSON_AddItemToObject(book_json, "curPage", cJSON_CreateNumber(book.curPage));
cJSON_AddItemToObject(book_json, "loadOver", cJSON_CreateBool(book.loadOver));
cJSON_AddItemToArray(json, book_json);
}
char *rendered = cJSON_Print(json);
std::ofstream file(filename);
if (!file.is_open()) {
static_print_error("Error: Unable to open file for writing: %s", filename);
cJSON_Delete(json);
free(rendered);
return;
}
static_print_info("File opened successfully. Writing JSON to file...");
static_print_debug("%s", rendered);
file << rendered;
file.close();
static_print_info("JSON written to file successfully.");
cJSON_Delete(json);
free(rendered);
}
// 扫描 txt 文件并更新书籍列表
void TjdUiAppEbookModel::ScanAndUpdateBooks(const char *dirname, std::list<EbookItem> &books)
{
DIR *d;
std::string dir = dirname;
struct dirent *dirp;
struct stat fileInfo;
d = opendir(dir.c_str());
if (d) {
uint8_t next_id = books.empty() ? 0 : books.back().id + 1;
while ((dirp = readdir(d)) != nullptr) {
std::string filename = dirp->d_name;
std::string fullpath = dir + "/" + filename;
if (stat(fullpath.c_str(), &fileInfo) == 0 && S_ISREG(fileInfo.st_mode) && fileInfo.st_size > 0) {
size_t pos = filename.rfind('.');
if (pos != std::string::npos && filename.substr(pos + 1) == "txt") {
std::string name = filename.substr(0, pos);
bool exists = false;
for (const auto &book : books) {
if (book.name == name) {
exists = true;
break;
}
}
if (!exists) {
books.emplace_back(next_id++, name, 1, 1, false);
}
}
}
}
closedir(d);
}
}
// 删除指定ID的书籍和对应的文件
bool TjdUiAppEbookModel::deleteBookById(const char *jsonFilePath, int id)
{
std::ifstream json_file(jsonFilePath);
if (!json_file.is_open()) {
static_print_error("Failed to open file: %s", jsonFilePath);
return false;
}
std::string json_str((std::istreambuf_iterator<char>(json_file)), std::istreambuf_iterator<char>());
json_file.close();
if (json_str.empty()) {
static_print_error("json has no content.");
return false;
}
cJSON *json = cJSON_Parse(json_str.c_str());
if (!cJSON_IsArray(json)) {
static_print_error("json is not Array");
cJSON_Delete(json);
return false;
}
static_print_debug("delete before...");
static_print_debug("%s", cJSON_Print(json));
delete_and_renumber_books(&json, id);
const char *output = cJSON_Print(json);
std::ofstream out_file(jsonFilePath);
if (out_file.is_open()) {
static_print_debug("delete after...");
static_print_debug("%s", output);
out_file << output;
out_file.close();
} else {
static_print_error("Failed to open file: %s", jsonFilePath);
free((void *)output);
cJSON_Delete(json);
return false;
}
free((void *)output);
cJSON_Delete(json);
return true;
}
void TjdUiAppEbookModel::SaveItemBookToJson(const char *filename, const EbookItem itemToUpdate)
{
std::ifstream file(filename);
if (!file.is_open()) {
static_print_error("Unable to open file: %s", filename);
return;
}
std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
cJSON *root = cJSON_Parse(fileContent.c_str());
if (root == nullptr || !cJSON_IsArray(root)) {
static_print_error("Parsing JSON failed or the JSON root is not an array.");
if (root != nullptr)
cJSON_Delete(root);
return;
}
int arraySize = cJSON_GetArraySize(root);
for (int i = 0; i < arraySize; ++i) {
cJSON *item = cJSON_GetArrayItem(root, i);
if (item != nullptr && cJSON_IsObject(item)) {
cJSON *itemId = cJSON_GetObjectItem(item, "id");
if (itemId != nullptr && cJSON_IsNumber(itemId) && itemId->valueint == itemToUpdate.id) {
// 找到匹配的项,更新字段
cJSON_SetNumberValue(cJSON_GetObjectItem(item, "curPage"), itemToUpdate.curPage);
cJSON *boolField = cJSON_GetObjectItem(item, "loadOver");
if (cJSON_IsBool(boolField)) {
cJSON_DeleteItemFromObject(item, "loadOver"); // 先删除旧的字段
cJSON_AddItemToObject(item, "loadOver", cJSON_CreateBool(itemToUpdate.loadOver));
}
break;
}
}
}
// 将修改后的JSON写回文件
char *jsonString = cJSON_Print(root);
if (jsonString == nullptr) {
static_print_error("Cannot convert JSON to a string.");
cJSON_Delete(root);
return;
}
std::ofstream outFile(filename);
if (!outFile.is_open()) {
static_print_error("Unable to open file for writing: %s", filename);
free(jsonString);
cJSON_Delete(root);
return;
}
outFile << jsonString;
outFile.close();
free(jsonString);
cJSON_Delete(root);
}
TjdUiAppEbookModel &TjdUiAppEbookModel::GetInstance(void)
{
static TjdUiAppEbookModel instance;
return instance;
}
} // namespace TJD