File indexing completed on 2024-05-12 17:24:10
0001 // SPDX-FileCopyrightText: 2023 Mathis <mbb@kaidan.im> 0002 // SPDX-License-Identifier: LGPL-2.0-or-later 0003 0004 #include "plantsmodel.h" 0005 #include <QCoroTask> 0006 #include <QCoroFuture> 0007 #include <QDateTime> 0008 0009 #include <unordered_map> 0010 #include <algorithm> 0011 0012 using namespace DB; 0013 0014 PlantsModel::PlantsModel(QObject *parent) 0015 : QAbstractListModel(parent) 0016 { 0017 auto future = Database::instance().plants(); 0018 0019 QCoro::connect(std::move(future), this, [this](auto &&plants) { 0020 beginResetModel(); 0021 m_data = plants; 0022 endResetModel(); 0023 Q_EMIT summaryChanged(); 0024 }); 0025 0026 connect(&Database::instance(), &Database::plantChanged, this, [this](DB::Plant::Id plantId) { 0027 const auto it = std::find_if(m_data.cbegin(), m_data.cend(), [plantId](const auto &plant) { 0028 return plantId == plant.plant_id; 0029 }); 0030 0031 if (it == m_data.cend()) { 0032 return; 0033 } 0034 0035 const int row = it - m_data.cbegin(); 0036 0037 auto future = Database::instance().plant(plantId); 0038 0039 QCoro::connect(std::move(future), this, [this, row](auto &&plant) { 0040 if (plant) { 0041 m_data[row] = plant.value(); 0042 const auto idx = index(row, 0); 0043 Q_EMIT dataChanged(idx, idx); 0044 Q_EMIT summaryChanged(); 0045 } 0046 }); 0047 }); 0048 } 0049 0050 int PlantsModel::rowCount(const QModelIndex &) const 0051 { 0052 return m_data.size(); 0053 } 0054 0055 QHash<int, QByteArray> PlantsModel::roleNames() const 0056 { 0057 return { 0058 {Role::PlantID, "plantId"}, 0059 {Role::Name, "name" }, 0060 {Role::Species, "species"}, 0061 {Role::ImgUrl, "imgUrl"}, 0062 {Role::WaterInterval, "waterInterval"}, 0063 {Role::Location, "location"}, 0064 {Role::DateOfBirth, "dateOfBirth"}, 0065 {Role::LastWatered, "lastWatered"}, 0066 {Role::WantsToBeWateredIn, "wantsToBeWateredIn"}, 0067 {Role::CurrentHealth, "currentHealth"}, 0068 }; 0069 } 0070 0071 QVariant PlantsModel::data(const QModelIndex &index, int role) const 0072 { 0073 Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)); 0074 0075 const auto plant = m_data.at(index.row()); 0076 0077 static std::unordered_map<int,std::vector<QDateTime>> waterEvents; 0078 0079 switch(role){ 0080 case Role::PlantID: 0081 return plant.plant_id; 0082 case Role::Name: 0083 return plant.name; 0084 case Role::Species: 0085 return plant.species; 0086 case Role::ImgUrl: 0087 return plant.img_url; 0088 case Role::WaterInterval: 0089 return plant.water_intervall; 0090 case Role::Location: 0091 return plant.location; 0092 case Role::DateOfBirth: 0093 return QDateTime::fromSecsSinceEpoch(plant.date_of_birth).date(); 0094 case Role::LastWatered: 0095 return QDateTime::fromSecsSinceEpoch(plant.last_watered).date(); 0096 case Role::WantsToBeWateredIn: 0097 return QDate::currentDate().daysTo(QDateTime::fromSecsSinceEpoch(plant.last_watered).date().addDays(plant.water_intervall)); 0098 case Role::CurrentHealth: 0099 return plant.current_health; 0100 }; 0101 0102 Q_UNREACHABLE(); 0103 } 0104 0105 void PlantsModel::addPlant(const QString &name, const QString &species, const QString &imgUrl, const int waterInterval, const QString location, const int dateOfBirth, const int health) 0106 { 0107 const int now = QDateTime::currentDateTime().toSecsSinceEpoch(); 0108 auto future = Database::instance().addPlant(name, species, imgUrl, waterInterval, location, dateOfBirth, now, now, health); 0109 0110 QCoro::connect(std::move(future), this, [=, this](auto &&result) { 0111 beginInsertRows({}, m_data.size(), m_data.size()); 0112 m_data.push_back(Plant{result, name, species, imgUrl, waterInterval, location, dateOfBirth, 1, now, now, health}); 0113 endInsertRows(); 0114 }); 0115 } 0116 0117 void PlantsModel::editPlant(const DB::Plant::Id plantId, const QString &name, const QString &species, const QString &imgUrl, const int waterIntervall, const QString location, const int dateOfBirth) 0118 { 0119 const int row = [&]() { 0120 const auto it = std::find_if(m_data.cbegin(), m_data.cend(), [plantId](const auto &plant) { 0121 return plantId == plant.plant_id; 0122 }); 0123 0124 Q_ASSERT(it != m_data.cend()); 0125 0126 return it - m_data.cbegin(); 0127 }(); 0128 0129 Database::instance().editPlant(plantId, name, species, imgUrl, waterIntervall, location, dateOfBirth); 0130 0131 const auto idx = index(row, 0); 0132 0133 auto &plant = m_data[row]; 0134 plant.name = name; 0135 plant.species = species; 0136 plant.img_url = imgUrl; 0137 plant.water_intervall = waterIntervall; 0138 plant.location = location; 0139 plant.date_of_birth = dateOfBirth; 0140 0141 emit dataChanged(idx, idx); 0142 } 0143 0144 void PlantsModel::deletePlant(const int plantId) 0145 { 0146 const int row = [&]() { 0147 const auto it = std::find_if(m_data.cbegin(), m_data.cend(), [plantId](const auto &plant) { 0148 return plantId == plant.plant_id; 0149 }); 0150 0151 Q_ASSERT(it != m_data.cend()); 0152 0153 return it - m_data.cbegin(); 0154 }(); 0155 0156 m_data.erase(m_data.begin() + row); 0157 0158 beginRemoveRows({}, row, row); 0159 Database::instance().deletePlant(plantId); 0160 endRemoveRows(); 0161 } 0162 0163 PlantsModel::Summary PlantsModel::summary() const 0164 { 0165 auto needsWatering = [](const Plant &plant) { 0166 auto lastWatered = QDateTime::fromSecsSinceEpoch(plant.last_watered).date(); 0167 auto daysTillWatering = QDate::currentDate().daysTo(lastWatered.addDays(plant.water_intervall)); 0168 return daysTillWatering <= 0; 0169 }; 0170 0171 if (std::any_of(m_data.begin(), m_data.end(), needsWatering)) { 0172 return Summary::SomeNeedWater; 0173 } 0174 0175 return Summary::NothingToDo; 0176 }