Files
gxde-ai-see/src/todo/todomodel.cpp
T
shenmo7192 3a73a8c5d1 feat(factory): 内容工厂与链接处理
- 第三栏内容工厂:按拖入类型展示动作,动作按钮本身可接收 drop
- 链接分类:http(s) 按扩展名判定图片/音视频/文档/压缩包/网页
- http 链接动作:打开、下载、另存为、复制、Markdown、复制文件名、待办、问小埃
- 非标准 scheme:尝试打开、复制;thunder 解析 base64 真实地址,magnet 解析 dn
- 文字动作:ICU 分词、正则提取链接、朗读(spd-say)、复制、待办
- 文件/图片动作:打开、提取文字(占位)、生成描述、保存图片、复制路径、待办
- Downloader:异步下载到 XDG 下载目录 / 另存为,面板 toast 提示
- TodoModel:持久化到 todo.json,供「添加到待办」使用
- 无头自测 gxde-ai-see-selftest:链接分类/分词/提取链接/动作匹配
- 合成器 portal 自测脚本 tests/portal(虚拟指针 + GTK 源/目标)
2026-10-30 20:09:01 +08:00

166 lines
4.1 KiB
C++

// SPDX-FileCopyrightText: 2026 GXDE OS Team
// SPDX-License-Identifier: GPL-3.0-or-later
#include "todomodel.h"
#include <QDateTime>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QSaveFile>
#include <QUuid>
#include "config.h"
TodoModel *TodoModel::instance()
{
static TodoModel *self = new TodoModel;
return self;
}
TodoModel::TodoModel(QObject *parent)
: QAbstractListModel(parent)
{
m_path = Config::instance()->dataDir() + QStringLiteral("/todo.json");
load();
}
int TodoModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_items.size();
}
QVariant TodoModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= m_items.size()) {
return QVariant();
}
const TodoItem &item = m_items.at(index.row());
switch (role) {
case Qt::DisplayRole:
case TextRole:
return item.text;
case DoneRole:
return item.done;
case IdRole:
return item.id;
default:
return QVariant();
}
}
bool TodoModel::removeRows(int row, int count, const QModelIndex &parent)
{
if (parent.isValid() || row < 0 || count <= 0 || row + count > m_items.size()) {
return false;
}
beginRemoveRows(QModelIndex(), row, row + count - 1);
for (int i = 0; i < count; ++i) {
m_items.removeAt(row);
}
endRemoveRows();
save();
Q_EMIT countChanged();
return true;
}
Qt::ItemFlags TodoModel::flags(const QModelIndex &index) const
{
return index.isValid() ? (Qt::ItemIsEnabled | Qt::ItemIsSelectable) : Qt::NoItemFlags;
}
void TodoModel::add(const QString &text)
{
const QString trimmed = text.trimmed();
if (trimmed.isEmpty()) {
return;
}
TodoItem item;
item.id = QUuid::createUuid().toString(QUuid::WithoutBraces);
item.text = trimmed;
item.createdAt = QDateTime::currentMSecsSinceEpoch();
beginInsertRows(QModelIndex(), 0, 0);
m_items.prepend(item);
endInsertRows();
save();
Q_EMIT countChanged();
}
void TodoModel::setDone(int row, bool done)
{
if (row < 0 || row >= m_items.size() || m_items[row].done == done) {
return;
}
m_items[row].done = done;
const QModelIndex idx = index(row);
Q_EMIT dataChanged(idx, idx, { DoneRole });
save();
}
const TodoItem *TodoModel::itemAt(int row) const
{
return (row >= 0 && row < m_items.size()) ? &m_items.at(row) : nullptr;
}
void TodoModel::load()
{
QFile file(m_path);
if (!file.open(QIODevice::ReadOnly)) {
return;
}
const QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
if (!doc.isObject()) {
return;
}
QList<TodoItem> items;
const QJsonArray array = doc.object().value(QStringLiteral("items")).toArray();
for (const QJsonValue &value : array) {
const QJsonObject object = value.toObject();
TodoItem item;
item.id = object.value(QStringLiteral("id")).toString();
item.text = object.value(QStringLiteral("text")).toString();
item.done = object.value(QStringLiteral("done")).toBool();
item.createdAt =
static_cast<qint64>(object.value(QStringLiteral("createdAt")).toDouble());
if (!item.text.isEmpty()) {
items.append(item);
}
}
if (items.isEmpty()) {
return;
}
beginResetModel();
m_items = items;
endResetModel();
Q_EMIT countChanged();
}
void TodoModel::save() const
{
QJsonArray array;
for (const TodoItem &item : m_items) {
QJsonObject object;
object.insert(QStringLiteral("id"), item.id);
object.insert(QStringLiteral("text"), item.text);
object.insert(QStringLiteral("done"), item.done);
object.insert(QStringLiteral("createdAt"), static_cast<double>(item.createdAt));
array.append(object);
}
QJsonObject root;
root.insert(QStringLiteral("version"), 1);
root.insert(QStringLiteral("items"), array);
QSaveFile file(m_path);
if (!file.open(QIODevice::WriteOnly)) {
return;
}
file.write(QJsonDocument(root).toJson(QJsonDocument::Indented));
file.commit();
}