File indexing completed on 2024-05-12 16:14:35

0001 // SPDX-FileCopyrightText: 2021 Han Young <hanyoung@protonmail.com>
0002 // SPDX-License-Identifier: LGPL-2.0-or-later
0003 
0004 #include "soundspickermodel.h"
0005 
0006 #include <vector>
0007 
0008 #include <QDirIterator>
0009 #include <QStandardPaths>
0010 
0011 class SoundsPickerModel::Private
0012 {
0013 public:
0014     QStringList defaultAudio;
0015     std::vector<QString> soundsVec;
0016     bool notification = false;
0017     QString theme = QStringLiteral("plasma-mobile");
0018 };
0019 
0020 SoundsPickerModel::SoundsPickerModel(QObject *parent)
0021     : QAbstractListModel(parent)
0022     , d(std::make_unique<Private>())
0023 {
0024     loadFiles();
0025 }
0026 
0027 void SoundsPickerModel::loadFiles()
0028 {
0029     d->soundsVec.clear();
0030     const auto locations = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
0031     const QString path = QStringLiteral("/sounds/") + d->theme + QStringLiteral("/stereo/");
0032 
0033     for (const auto &directory : locations) {
0034         if (QDir(directory + path).exists()) {
0035             QString subPath = directory + path;
0036             if (!d->notification && QDir(subPath + QStringLiteral("ringtone")).exists()) {
0037                 subPath += QStringLiteral("ringtone");
0038             } else if (d->notification && QDir(subPath + QStringLiteral("notification")).exists()) {
0039                 subPath += QStringLiteral("notification");
0040             }
0041 
0042             QDirIterator it(subPath, QDir::Files, QDirIterator::Subdirectories);
0043             while (it.hasNext()) {
0044                 d->soundsVec.push_back(it.next());
0045             }
0046         }
0047     }
0048 }
0049 
0050 SoundsPickerModel::~SoundsPickerModel() = default;
0051 
0052 QHash<int, QByteArray> SoundsPickerModel::roleNames() const
0053 {
0054     return {
0055         {Roles::NameRole, QByteArrayLiteral("ringtoneName")},
0056         {Roles::UrlRole, QByteArrayLiteral("sourceUrl")}
0057     };
0058 }
0059 
0060 bool SoundsPickerModel::notification() const
0061 {
0062     return d->notification;
0063 }
0064 
0065 void SoundsPickerModel::setNotification(bool notification)
0066 {
0067     if (d->notification == notification) {
0068         return;
0069     }
0070     d->notification = notification;
0071 
0072     bool needReset = false;
0073     QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/") + d->theme + QStringLiteral("/stereo/");
0074     if (!d->notification && QDir(path + QStringLiteral("ringtone")).exists()) {
0075         needReset = true;
0076     } else if (d->notification && QDir(path + QStringLiteral("notification")).exists()) {
0077         needReset = true;
0078     }
0079 
0080     if (needReset) {
0081         beginResetModel();
0082         loadFiles();
0083         endResetModel();
0084         rearrangeRingtoneOrder();
0085     }
0086 }
0087 
0088 QString SoundsPickerModel::initialSourceUrl(int index)
0089 {
0090     if (index >= 0 && index < (int)d->soundsVec.size()) {
0091         return d->soundsVec.at(index);
0092     }
0093     return {};
0094 }
0095 
0096 QVariant SoundsPickerModel::data(const QModelIndex &index, int role) const
0097 {
0098     if (!index.isValid() || index.row() < 0 || index.row() >= (int)d->soundsVec.size()) {
0099         return {};
0100     }
0101 
0102     if (role == NameRole) {
0103         auto ret = d->soundsVec.at(index.row());
0104         int suffixPos = ret.lastIndexOf(QLatin1Char('.'));
0105         if (suffixPos > 0) {
0106             ret.truncate(suffixPos);
0107         }
0108         int pathPos =  ret.lastIndexOf(QLatin1Char('/'));
0109         if (pathPos >= 0) {
0110             ret.remove(0, pathPos + 1);
0111         }
0112         return ret;
0113     }
0114     return d->soundsVec.at(index.row());
0115 }
0116 int SoundsPickerModel::rowCount(const QModelIndex& parent) const {
0117     Q_UNUSED(parent)
0118     return d->soundsVec.size();
0119 }
0120 
0121 const QStringList &SoundsPickerModel::defaultAudio() const
0122 {
0123     return d->defaultAudio;
0124 }
0125 
0126 void SoundsPickerModel::setDefaultAudio(const QStringList &audio)
0127 {
0128     d->defaultAudio = audio;
0129     rearrangeRingtoneOrder();
0130 }
0131 
0132 const QString &SoundsPickerModel::theme() const
0133 {
0134     return d->theme;
0135 }
0136 
0137 void SoundsPickerModel::setTheme(const QString &theme)
0138 {
0139     if (d->theme == theme) {
0140         return;
0141     }
0142     d->theme = theme;
0143 
0144     beginResetModel();
0145     loadFiles();
0146     endResetModel();
0147     rearrangeRingtoneOrder();
0148 }
0149 
0150 void SoundsPickerModel::rearrangeRingtoneOrder()
0151 {
0152     auto i {0};
0153     for (int j = 0; j < (int)d->soundsVec.size(); j++) {
0154         if (d->defaultAudio.contains(data(index(j), NameRole).toString())) {
0155             std::swap(d->soundsVec[j], d->soundsVec[i]);
0156             Q_EMIT dataChanged(index(j), index(j));
0157             Q_EMIT dataChanged(index(i), index(i));
0158             i++;
0159         }
0160     }
0161 }
0162 
0163 #include "moc_soundspickermodel.cpp"