diff options
author | jan Iversen <jan@casacondor.com> | 2020-01-24 13:31:51 +0100 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2020-01-27 14:25:03 -0800 |
commit | 6cd46bee063f3cc90934480cba3f8fb7908149bd (patch) | |
tree | b89902837e68a908e897504b730796ed9cb72cd4 | |
parent | bb13065a75fd02d0732575b2c01cb3210ad96f32 (diff) | |
download | subsurface-6cd46bee063f3cc90934480cba3f8fb7908149bd.tar.gz |
divesummary: add DiveSummary class to shared and backend
Create DiveSummary class in backend-shared and make the DiveSummary calculation
results available to QML.
This adds a loop over all dives (could have been done with a model, but the
models available to mobile are very limited, so use the basic way).
[Dirk Hohndel: renamed the results variable and combined a couple of commits]
Signed-off-by: jan Iversen <jan@casacondor.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r-- | backend-shared/CMakeLists.txt | 1 | ||||
-rw-r--r-- | backend-shared/divesummary.cpp | 169 | ||||
-rw-r--r-- | backend-shared/divesummary.h | 28 | ||||
-rw-r--r-- | mobile-widgets/qmlinterface.cpp | 12 | ||||
-rw-r--r-- | mobile-widgets/qmlinterface.h | 11 | ||||
-rw-r--r-- | packaging/ios/Subsurface-mobile.pro | 2 |
6 files changed, 222 insertions, 1 deletions
diff --git a/backend-shared/CMakeLists.txt b/backend-shared/CMakeLists.txt index fdfdb1e05..4ecd58074 100644 --- a/backend-shared/CMakeLists.txt +++ b/backend-shared/CMakeLists.txt @@ -1,6 +1,7 @@ # backend functionality shared between Desktop (UI) and Mobile (QML) set(BACKEND_SRCS + divesummary.cpp exportfuncs.cpp exportfuncs.h plannershared.cpp diff --git a/backend-shared/divesummary.cpp b/backend-shared/divesummary.cpp new file mode 100644 index 000000000..43f34a7ff --- /dev/null +++ b/backend-shared/divesummary.cpp @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "divesummary.h" +#include "core/qthelper.h" +#include "core/settings/qPrefUnit.h" + +#include <QDateTime> + +QStringList diveSummary::diveSummaryText; + +timestamp_t diveSummary::firstDive, diveSummary::lastDive; +int diveSummary::dives[2], diveSummary::divesEAN[2], diveSummary::divesDeep[2], diveSummary::diveplans[2]; +long diveSummary::divetime[2], diveSummary::depth[2], diveSummary::sac[2]; +long diveSummary::divetimeMax[2], diveSummary::depthMax[2], diveSummary::sacMin[2]; + +void diveSummary::summaryCalculation(int primaryPeriod, int secondaryPeriod) +{ + QDateTime localTime; + + // Calculate Start of the 2 periods. + timestamp_t now, primaryStart, secondaryStart; + now = QDateTime::currentMSecsSinceEpoch() / 1000L + gettimezoneoffset(); + primaryStart = (primaryPeriod == 0) ? 0 : now - primaryPeriod * 30 * 24 * 60 * 60; + secondaryStart = (secondaryPeriod == 0) ? 0 : now - secondaryPeriod * 30 * 24 * 60 * 60; + + // Loop over all dives and sum up data + loopDives(primaryStart, secondaryStart); + + // prepare stringlist + diveSummaryText.clear(); + diveSummaryText << "??" << "??" << "??" << "??" << "??" << + "??" << "??" << "??" << + "?:??" << "?:??" << "?:??" << + "?:??" << "?:??" << "?:??" << + "??" << "??" << "??" << "??" << "??" << + "??" << "??" << "??" << "??" << "??"; + + // set oldest/newest date + if (firstDive) { + localTime = QDateTime::fromMSecsSinceEpoch(1000 * firstDive, Qt::UTC); + localTime.setTimeSpec(Qt::UTC); + diveSummaryText[0] = QStringLiteral("%1").arg(localTime.date().toString(prefs.date_format_short)); + } + if (lastDive) { + localTime = QDateTime::fromMSecsSinceEpoch(1000 * lastDive, Qt::UTC); + localTime.setTimeSpec(Qt::UTC); + diveSummaryText[1] = QStringLiteral("%1").arg(localTime.date().toString(prefs.date_format_short)); + } + + // and add data + buildStringList(0); + buildStringList(1); +} + +void diveSummary::loopDives(timestamp_t primaryStart, timestamp_t secondaryStart) +{ + struct dive *dive; + int i; + + // Clear summary data + firstDive = lastDive = 0; + dives[0] = dives[1] = divesEAN[0] = divesEAN[1] = 0; + divesDeep[0] = divesDeep[1] = diveplans[0] = diveplans[1] = 0; + divetime[0] = divetime[1] = depth[0] = depth[1] = 0; + sac[0] = sac[1] = 0; + divetimeMax[0] = divetimeMax[1] = depthMax[0] = depthMax[1] = 0; + sacMin[0] = sacMin[1] = 99999; + + for_each_dive (i, dive) { + // remember time of oldest and newest dive + if (i == 0) + firstDive = dive->when; + if (dive->when > lastDive) + lastDive = dive->when; + + // check if dive is newer than primaryStart (add to first column) + if (dive->when > primaryStart) { + if (is_dc_planner(&dive->dc)) + diveplans[0]++; + else + calculateDive(0, dive); + } + + // check if dive is newer than secondaryStart (add to second column) + if (dive->when > secondaryStart) { + if (is_dc_planner(&dive->dc)) + diveplans[1]++; + else + calculateDive(1, dive); + } + } +} + +void diveSummary::calculateDive(int inx, struct dive *dive) +{ + long temp; + + // one more real dive + dives[inx]++; + + // sum dive in minutes and check for new max. + temp = dive->duration.seconds / 60; + divetime[inx] += temp; + if (temp > divetimeMax[inx]) + divetimeMax[inx] = temp; + + // sum depth in meters, check for new max. and if dive is a deep dive + temp = dive->maxdepth.mm / 1000; + depth[inx] += temp; + if (temp > depthMax[inx]) + depthMax[inx] = temp; + if (temp > 39) + divesDeep[inx]++; + + // sum SAC in liters, check for new max. + temp = dive->sac / 1000; + sac[inx] += temp; + if (temp < sacMin[inx]) + sacMin[inx] = temp; + + // EAN dive ? + for (int j = 0; j < dive->cylinders.nr; ++j) { + if (dive->cylinders.cylinders[j].gasmix.o2.permille > 210) + divesEAN[inx]++; + } +} + +void diveSummary::buildStringList(int inx) +{ + int temp1, temp2; + QString tempStr; + + if (!dives[inx]) + return; + + // dives + diveSummaryText[2+inx] = QStringLiteral("%1").arg(dives[inx]); + diveSummaryText[4+inx] = QStringLiteral("%1").arg(divesEAN[inx]); + diveSummaryText[6+inx] = QStringLiteral("%1").arg(divesDeep[inx]); + + // time + temp1 = divetime[inx] / 60; + temp2 = divetime[inx] - temp1 * 60; + if (temp1 >= 100) + diveSummaryText[8+inx] = QStringLiteral("%1h").arg(temp1); + else + diveSummaryText[8+inx] = QStringLiteral("%1:%2").arg(temp1).arg(temp2); + temp1 = divetimeMax[inx] / 60; + temp2 = divetimeMax[inx] - temp1 * 60; + diveSummaryText[10+inx] = QStringLiteral("%1:%2").arg(temp1).arg(temp2); + temp2 = divetime[inx] / dives[inx]; + temp1 = temp2 / 60; + temp2 = temp2 - temp1 * 60; + diveSummaryText[12+inx] = QStringLiteral("%1:%2").arg(temp1).arg(temp2); + + // depth + tempStr = (qPrefUnits::length() == units::METERS) ? "m" : "ft"; + diveSummaryText[14+inx] = QStringLiteral("%1%2").arg(depthMax[inx]).arg(tempStr); + temp1 = depth[inx] / dives[inx]; + diveSummaryText[16+inx] = QStringLiteral("%1%2").arg(temp1).arg(tempStr); + + // SAC + tempStr = (qPrefUnits::volume() == units::LITER) ? "l/min" : "cuft/min"; + diveSummaryText[18+inx] = QStringLiteral("%1 %2").arg(sacMin[inx]).arg(tempStr); + temp1 = depth[inx] / dives[inx]; + diveSummaryText[20+inx] = QStringLiteral("%1%2").arg(temp1).arg(tempStr); + + // Diveplan(s) + diveSummaryText[22+inx] = QStringLiteral("%1").arg(diveplans[inx]); +} diff --git a/backend-shared/divesummary.h b/backend-shared/divesummary.h new file mode 100644 index 000000000..16f8a09ec --- /dev/null +++ b/backend-shared/divesummary.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef DIVESUMMARY_H +#define DIVESUMMARY_H +#include <QStringList> +#include "core/dive.h" + + +class diveSummary { + +public: + static void summaryCalculation(int primaryPeriod, int secondaryPeriod); + + static QStringList diveSummaryText; + +private: + diveSummary() {} + + static void loopDives(timestamp_t primaryStart, timestamp_t secondaryStart); + static void calculateDive(int inx, struct dive *dive); + static void buildStringList(int inx); + + static timestamp_t firstDive, lastDive; + static int dives[2], divesEAN[2], divesDeep[2], diveplans[2]; + static long divetime[2], depth[2], sac[2]; + static long divetimeMax[2], depthMax[2], sacMin[2]; + static long divetimeAvg[2], depthAvg[2], sacAvg[2]; +}; +#endif // DIVESUMMARY_H diff --git a/mobile-widgets/qmlinterface.cpp b/mobile-widgets/qmlinterface.cpp index df3af0b5f..f666d2dc0 100644 --- a/mobile-widgets/qmlinterface.cpp +++ b/mobile-widgets/qmlinterface.cpp @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include "qmlinterface.h" - #include <QQmlEngine> QMLInterface *QMLInterface::instance() @@ -92,4 +91,15 @@ void QMLInterface::setup(QQmlContext *ct) instance(), &QMLInterface::verbatim_planChanged); connect(qPrefDivePlanner::instance(), &qPrefDivePlanner::display_variationsChanged, instance(), &QMLInterface::display_variationsChanged); + + // calculate divesummary first time. + // this is needed in order to load the divesummary page + diveSummary::summaryCalculation(0, 3); +} + + +void QMLInterface::summaryCalculation(int primaryPeriod, int secondaryPeriod) +{ + diveSummary::summaryCalculation(primaryPeriod, secondaryPeriod); + emit diveSummaryTextChanged(diveSummary::diveSummaryText); } diff --git a/mobile-widgets/qmlinterface.h b/mobile-widgets/qmlinterface.h index 9b032505a..45a39206e 100644 --- a/mobile-widgets/qmlinterface.h +++ b/mobile-widgets/qmlinterface.h @@ -7,9 +7,12 @@ #include "core/settings/qPrefTechnicalDetails.h" #include "qt-models/diveplannermodel.h" #include "backend-shared/plannershared.h" +#include "backend-shared/divesummary.h" #include <QObject> #include <QQmlContext> +#include <QStringList> + // This class is a pure interface class and may not contain any implementation code // Allowed are: // header @@ -74,6 +77,8 @@ class QMLInterface : public QObject { Q_PROPERTY(bool verbatim_plan READ verbatim_plan WRITE set_verbatim_plan NOTIFY verbatim_planChanged); Q_PROPERTY(bool display_variations READ display_variations WRITE set_display_variations NOTIFY display_variationsChanged); + Q_PROPERTY(QStringList diveSummaryText READ diveSummaryText NOTIFY diveSummaryTextChanged); + public: static QMLInterface *instance(); @@ -163,6 +168,9 @@ public: }; Q_ENUM(DIVE_MODE); + // Function to calculate dive summary + Q_INVOKABLE void summaryCalculation(int primaryPeriod, int secondaryPeriod); + public: CLOUD_STATUS cloud_verification_status() { return (CLOUD_STATUS)prefs.cloud_verification_status; } DURATION duration_units() { return (DURATION)prefs.units.duration_units; } @@ -209,6 +217,8 @@ public: bool verbatim_plan() { return prefs.verbatim_plan; } bool display_variations() { return prefs.display_variations; } + const QStringList &diveSummaryText() { return diveSummary::diveSummaryText; } + public slots: void set_cloud_verification_status(CLOUD_STATUS value) { qPrefCloudStorage::set_cloud_verification_status(value); } void set_duration_units(DURATION value) { qPrefUnits::set_duration_units((units::DURATION)value); } @@ -301,6 +311,7 @@ signals: void verbatim_planChanged(bool value); void display_variationsChanged(bool value); + void diveSummaryTextChanged(QStringList); private: QMLInterface() {} }; diff --git a/packaging/ios/Subsurface-mobile.pro b/packaging/ios/Subsurface-mobile.pro index aafb52549..60ea99f58 100644 --- a/packaging/ios/Subsurface-mobile.pro +++ b/packaging/ios/Subsurface-mobile.pro @@ -108,6 +108,7 @@ SOURCES += ../../subsurface-mobile-main.cpp \ ../../core/subsurface-qt/CylinderObjectHelper.cpp \ ../../core/subsurface-qt/DiveObjectHelper.cpp \ ../../core/subsurface-qt/DiveListNotifier.cpp \ + ../../backend-shared/divesummary.cpp \ ../../backend-shared/exportfuncs.cpp \ ../../backend-shared/plannershared.cpp \ ../../mobile-widgets/qmlinterface.cpp \ @@ -242,6 +243,7 @@ HEADERS += \ ../../core/subsurface-qt/CylinderObjectHelper.h \ ../../core/subsurface-qt/DiveObjectHelper.h \ ../../core/subsurface-qt/DiveListNotifier.h \ + ../../backend-shared/divesummary.h \ ../../backend-shared/exportfuncs.h \ ../../backend-shared/plannershared.h \ ../../mobile-widgets/qmlinterface.h \ |