amnezia-client/client/ui/models/newsmodel.cpp
2025-06-20 04:23:32 +04:00

195 lines
No EOL
5 KiB
C++

#include "ui/models/newsmodel.h"
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonValue>
#include <QQmlEngine>
#include <QFile>
#include <QDir>
#include <QStandardPaths>
#include <QJsonDocument>
#include <algorithm>
NewsModel::NewsModel(QObject *parent)
: QAbstractListModel(parent)
{
loadLocalNews();
}
int NewsModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_items.size();
}
QVariant NewsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= m_items.size())
return QVariant();
const NewsItem &item = m_items.at(index.row());
switch (role) {
case IdRole:
return item.id;
case TitleRole:
return item.title;
case ContentRole:
return item.content;
case TimestampRole:
return item.timestamp.toString(Qt::ISODate);
case IsReadRole:
return item.read;
case IsProcessedRole:
return index.row() == m_processedIndex;
default:
return QVariant();
}
}
QHash<int, QByteArray> NewsModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[IdRole] = "id";
roles[TitleRole] = "title";
roles[ContentRole] = "content";
roles[TimestampRole] = "timestamp";
roles[IsReadRole] = "read";
roles[IsProcessedRole] = "isProcessed";
return roles;
}
void NewsModel::markAsRead(int index)
{
if (index < 0 || index >= m_items.size())
return;
if (!m_items[index].read) {
m_items[index].read = true;
QModelIndex idx = createIndex(index, 0);
emit dataChanged(idx, idx, {IsReadRole});
emit hasUnreadChanged();
}
}
int NewsModel::processedIndex() const
{
return m_processedIndex;
}
void NewsModel::setProcessedIndex(int index)
{
if (index < 0 || index >= m_items.size() || m_processedIndex == index)
return;
m_processedIndex = index;
emit processedIndexChanged(index);
}
void NewsModel::updateModel(const QJsonArray &serverItems)
{
QSet<QString> existingIds;
for (const NewsItem &item : m_items) {
existingIds.insert(item.id);
}
QList<NewsItem> newItems;
for (const QJsonValue &value : serverItems) {
if (!value.isObject()) continue;
const QJsonObject obj = value.toObject();
QString id = obj.value("id").toString();
if (!existingIds.contains(id)) {
NewsItem item;
item.id = id;
item.title = obj.value("header").toString();
item.content = obj.value("content").toString();
item.timestamp = QDateTime::fromString(obj.value("timestamp").toString(), Qt::ISODate);
item.read = false; // New news is always unread
newItems.append(item);
existingIds.insert(id);
}
}
if (!newItems.isEmpty()) {
beginResetModel();
m_items.append(newItems);
// Sort descending by timestamp (newest first)
std::sort(m_items.begin(), m_items.end(), [](const NewsItem &a, const NewsItem &b) {
return a.timestamp > b.timestamp;
});
endResetModel();
emit hasUnreadChanged();
}
}
bool NewsModel::hasUnread() const
{
for (const NewsItem &item : m_items) {
if (!item.read)
return true;
}
return false;
}
QString NewsModel::localFilePath() const
{
QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QDir dir(path);
if (!dir.exists()) {
dir.mkpath(".");
}
return path + "/news.json";
}
void NewsModel::loadLocalNews()
{
QFile file(localFilePath());
if (!file.exists() || !file.open(QIODevice::ReadOnly)) {
return;
}
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
file.close();
if (!doc.isArray()) {
return;
}
beginResetModel();
m_items.clear();
QJsonArray newsArray = doc.array();
for (const QJsonValue &value : newsArray) {
if (!value.isObject())
continue;
const QJsonObject obj = value.toObject();
NewsItem item;
item.id = obj.value("id").toString();
item.title = obj.value("header").toString();
item.content = obj.value("content").toString();
item.timestamp = QDateTime::fromString(obj.value("timestamp").toString(), Qt::ISODate);
item.read = obj.value("read").toBool();
m_items.append(item);
}
endResetModel();
}
void NewsModel::saveLocalNews() const
{
QJsonArray newsArray;
for (const auto &item : m_items) {
QJsonObject obj;
obj["id"] = item.id;
obj["header"] = item.title;
obj["content"] = item.content;
obj["timestamp"] = item.timestamp.toString(Qt::ISODate);
obj["read"] = item.read;
newsArray.append(obj);
}
QJsonDocument doc(newsArray);
QFile file(localFilePath());
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
file.write(doc.toJson());
file.close();
} else {
qWarning() << "Could not save news to" << localFilePath();
}
}