File indexing completed on 2024-05-12 17:21:22

0001 /*
0002  * SPDX-FileCopyrightText: 2020 Jonah BrĂ¼chert <jbb@kaidan.im>
0003  * SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
0004  *
0005  * SPDX-License-Identifier: GPL-3.0-or-later
0006  */
0007 
0008 #include "recordingmodel.h"
0009 
0010 #include <QFile>
0011 #include <QStandardPaths>
0012 #include <QJsonObject>
0013 #include <QDebug>
0014 #include <QJsonDocument>
0015 #include <QJsonArray>
0016 #include <QDir>
0017 
0018 #include "utils.h"
0019 
0020 const QString DEF_RECORD_PREFIX = QStringLiteral("clip");
0021 
0022 RecordingModel* RecordingModel::instance()
0023 {
0024     static RecordingModel *recordingModel = new RecordingModel(qApp);
0025     return recordingModel;
0026 }
0027 
0028 RecordingModel::RecordingModel(QObject *parent) 
0029     : QAbstractListModel{ parent }
0030     , m_settings{ new QSettings(parent) }
0031 {
0032     load();
0033 }
0034 
0035 RecordingModel::~RecordingModel()
0036 {
0037     save();
0038 }
0039 
0040 int RecordingModel::count() const
0041 {
0042     return m_recordings.size();
0043 }
0044 
0045 void RecordingModel::load()
0046 {
0047     QJsonDocument doc = QJsonDocument::fromJson(m_settings->value(QStringLiteral("recordings")).toString().toUtf8());
0048 
0049     beginResetModel();
0050     
0051     const auto array = doc.array();
0052     std::transform(array.begin(), array.end(), std::back_inserter(m_recordings), [this](const QJsonValue &rec) {
0053         return new Recording(this, rec.toObject());
0054     });
0055     
0056     // check if file exists, and delete recording if it doesn't
0057     for (int i = 0; i < m_recordings.size(); ++i) {
0058         if (!QFile::exists(m_recordings[i]->filePath())) {
0059             m_recordings.erase(m_recordings.begin() + i);
0060             --i;
0061         }
0062     }
0063     save();
0064     
0065     endResetModel();
0066     Q_EMIT countChanged();
0067 }
0068 
0069 void RecordingModel::save()
0070 {
0071     QJsonArray arr;
0072 
0073     const auto recordings = qAsConst(m_recordings);
0074     std::transform(recordings.begin(), recordings.end(), std::back_inserter(arr), [](const Recording *recording) {
0075         return QJsonValue(recording->toJson());
0076     });
0077     
0078     m_settings->setValue(QStringLiteral("recordings"), QString::fromStdString(QJsonDocument(arr).toJson(QJsonDocument::Compact).toStdString()));
0079     m_settings->sync();
0080 }
0081 
0082 int RecordingModel::rowCount(const QModelIndex &parent) const
0083 {
0084     if (parent.isValid()) {
0085         return 0;
0086     }
0087     return m_recordings.size();
0088 }
0089 
0090 QVariant RecordingModel::data(const QModelIndex &index, int role) const
0091 {
0092     if (!checkIndex(index)) {
0093         return QVariant();
0094     }
0095     if (role != RecordingRole) {
0096         return QVariant();
0097     }
0098 
0099     auto *recording = m_recordings[index.row()];
0100     return recording ? QVariant::fromValue(recording) : QVariant();
0101 }
0102 
0103 QHash<int, QByteArray> RecordingModel::roleNames() const
0104 {
0105     return {{RecordingRole, "recording"}};
0106 }
0107 
0108 QList<Recording *> &RecordingModel::recordings()
0109 {
0110     return m_recordings;
0111 }
0112 
0113 QString RecordingModel::nextDefaultRecordingName()
0114 {
0115     // used names set
0116     QSet<QString> usedNames;
0117 
0118     for (const auto &rec : qAsConst(m_recordings)) {
0119         usedNames.insert(rec->fileName());
0120     }
0121     
0122     // add files in storage location
0123     QDir storageLocation{QStandardPaths::writableLocation(QStandardPaths::MusicLocation)};
0124     for (QFileInfo &info : storageLocation.entryInfoList()) {
0125         auto name = info.fileName();
0126         auto list = name.split(QStringLiteral("."));
0127         
0128         // insert without file extension
0129         if (list.size() > 0) {
0130             usedNames.insert(list[0]);
0131         }
0132     }
0133 
0134     // determine valid clip name (ex. clip_0001, clip_0002, etc.)
0135     
0136     int num = 1;
0137     QString build = QStringLiteral("0001");
0138         
0139     while (usedNames.contains(DEF_RECORD_PREFIX + QStringLiteral("_") + build)) {
0140         num++;
0141         build = QString::number(num);
0142         while (build.length() < 4) {
0143             build = QStringLiteral("0") + build;
0144         }
0145     }
0146     
0147     return DEF_RECORD_PREFIX + QStringLiteral("_") + build;
0148 }
0149 
0150 
0151 void RecordingModel::insertRecording(QString filePath, QString fileName, QDateTime recordDate, int recordingLength)
0152 {
0153     qDebug() << "Adding recording " << filePath;
0154 
0155     beginInsertRows(QModelIndex(), 0, 0);
0156     
0157     m_recordings.insert(0, new Recording(this, filePath, fileName, recordDate, recordingLength));
0158     save();
0159     
0160     endInsertRows();
0161     Q_EMIT countChanged();
0162 }
0163 
0164 void RecordingModel::deleteRecording(const int index)
0165 {
0166     qDebug() << "Removing recording " << m_recordings[index]->filePath();
0167     
0168     beginRemoveRows(QModelIndex(), index, index);
0169 
0170     QFile::remove(m_recordings[index]->filePath());
0171     m_recordings.removeAt(index);
0172     save();
0173 
0174     endRemoveRows();
0175     Q_EMIT countChanged();
0176 }
0177