File indexing completed on 2024-03-24 17:28:04
0001 // SPDX-FileCopyrightText: 2022 Felipe Kinoshita <kinofhek@gmail.com> 0002 // SPDX-License-Identifier: LGPL-2.1-or-later 0003 0004 #include "tasksmodel.h" 0005 #include "tasks_debug.h" 0006 0007 #include <QStandardPaths> 0008 #include <QFile> 0009 #include <QDir> 0010 0011 #include <QJsonArray> 0012 #include <QJsonDocument> 0013 #include <QJsonObject> 0014 0015 TasksModel::TasksModel(QObject *parent) 0016 : QAbstractListModel(parent) 0017 { 0018 loadTasks(); 0019 } 0020 0021 QHash<int, QByteArray> TasksModel::roleNames() const 0022 { 0023 return { 0024 {Roles::TitleRole, QByteArrayLiteral("title")}, 0025 {Roles::CheckedRole, QByteArrayLiteral("checked")} 0026 }; 0027 } 0028 0029 QVariant TasksModel::data(const QModelIndex &index, int role) const 0030 { 0031 if (!index.isValid() || index.row() < 0 || index.row() >= m_tasks.count()) { 0032 return {}; 0033 } 0034 0035 auto task = m_tasks.at(index.row()); 0036 0037 switch (role) { 0038 case Roles::TitleRole: 0039 return task.title(); 0040 case Roles::CheckedRole: 0041 return task.checked(); 0042 } 0043 0044 return {}; 0045 } 0046 0047 int TasksModel::rowCount(const QModelIndex &parent) const 0048 { 0049 Q_UNUSED(parent) 0050 return m_tasks.size(); 0051 } 0052 0053 bool TasksModel::setData(const QModelIndex &index, const QVariant &value, int role) 0054 { 0055 if (index.row() < 0 || index.row() >= m_tasks.count()) { 0056 return false; 0057 } 0058 0059 auto& task = m_tasks[index.row()]; 0060 0061 switch (role) { 0062 case Roles::CheckedRole: 0063 task.setChecked(value.toBool()); 0064 0065 if (task.checked()) { 0066 m_completedTasks++; 0067 Q_EMIT completedTasksChanged(); 0068 } 0069 0070 if (!task.checked()) { 0071 if (m_completedTasks > 0) { 0072 m_completedTasks--; 0073 Q_EMIT completedTasksChanged(); 0074 } 0075 } 0076 0077 break; 0078 case Roles::TitleRole: 0079 task.setTitle(value.toString()); 0080 break; 0081 } 0082 0083 Q_EMIT dataChanged(index, index, { role }); 0084 0085 saveTasks(); 0086 0087 return true; 0088 } 0089 0090 void TasksModel::add(const QString &title) 0091 { 0092 Task t(title, false); 0093 0094 beginInsertRows(QModelIndex(), m_tasks.count(), m_tasks.count()); 0095 m_tasks.append(t); 0096 endInsertRows(); 0097 0098 saveTasks(); 0099 } 0100 0101 void TasksModel::remove(const QModelIndex &index) 0102 { 0103 const int row = index.row(); 0104 if (row < 0 || row > m_tasks.count()) { 0105 return; 0106 } 0107 0108 if (m_tasks[row].checked()) { 0109 if (m_completedTasks > 0) { 0110 m_completedTasks--; 0111 Q_EMIT completedTasksChanged(); 0112 } 0113 } 0114 0115 beginRemoveRows(QModelIndex(), row, row); 0116 m_tasks.removeAt(row); 0117 endRemoveRows(); 0118 0119 saveTasks(); 0120 } 0121 0122 void TasksModel::clear() 0123 { 0124 beginResetModel(); 0125 m_tasks.clear(); 0126 endResetModel(); 0127 0128 saveTasks(); 0129 } 0130 0131 bool TasksModel::saveTasks() const 0132 { 0133 const QString outputDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); 0134 0135 QFile outputFile(outputDir + QStringLiteral("/tasks.json")); 0136 if (!QDir(outputDir).mkpath(QStringLiteral("."))) { 0137 qCWarning(TASKS_LOG) << "Destdir doesn't exist and I can't create it: " << outputDir; 0138 return false; 0139 } 0140 if (!outputFile.open(QIODevice::WriteOnly)) { 0141 qCWarning(TASKS_LOG) << "Failed to write tabs to disk"; 0142 } 0143 0144 QJsonArray tasksArray; 0145 std::transform(m_tasks.cbegin(), m_tasks.cend(), std::back_inserter(tasksArray), [](const Task &task) { 0146 return task.toJson(); 0147 }); 0148 0149 qCDebug(TASKS_LOG) << "Wrote to file" << outputFile.fileName() << "(" << tasksArray.count() << "tasks" << ")"; 0150 0151 const QJsonDocument document({ 0152 {QLatin1String("tasks"), tasksArray}, 0153 {QLatin1String("completedTasks"), m_completedTasks} 0154 }); 0155 0156 outputFile.write(document.toJson()); 0157 0158 return true; 0159 } 0160 0161 bool TasksModel::loadTasks() 0162 { 0163 beginResetModel(); 0164 0165 const QString input = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/tasks.json"); 0166 0167 QFile inputFile(input); 0168 if (!inputFile.exists()) { 0169 return false; 0170 } 0171 0172 if (!inputFile.open(QIODevice::ReadOnly)) { 0173 qCWarning(TASKS_LOG) << "Failed to load tabs from disk"; 0174 } 0175 0176 const auto tasksStorage = QJsonDocument::fromJson(inputFile.readAll()).object(); 0177 m_tasks.clear(); 0178 0179 m_completedTasks = tasksStorage.value(QLatin1String("completedTasks")).toInt(); 0180 0181 const auto tasks = tasksStorage.value(QLatin1String("tasks")).toArray(); 0182 0183 std::transform(tasks.cbegin(), tasks.cend(), std::back_inserter(m_tasks), [](const QJsonValue &task) { 0184 return Task::fromJson(task.toObject()); 0185 }); 0186 0187 qCDebug(TASKS_LOG) << "loaded from file:" << m_tasks.count() << input; 0188 0189 endResetModel(); 0190 0191 return true; 0192 }