mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									bb13065a75
								
							
						
					
					
						commit
						6cd46bee06
					
				
					 6 changed files with 222 additions and 1 deletions
				
			
		|  | @ -1,6 +1,7 @@ | |||
| # backend functionality shared between Desktop (UI) and Mobile (QML) | ||||
| 
 | ||||
| set(BACKEND_SRCS | ||||
| 	divesummary.cpp | ||||
| 	exportfuncs.cpp | ||||
| 	exportfuncs.h | ||||
| 	plannershared.cpp | ||||
|  |  | |||
							
								
								
									
										169
									
								
								backend-shared/divesummary.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								backend-shared/divesummary.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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]); | ||||
| } | ||||
							
								
								
									
										28
									
								
								backend-shared/divesummary.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								backend-shared/divesummary.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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
 | ||||
|  | @ -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); | ||||
| } | ||||
|  |  | |||
|  | @ -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() {} | ||||
| }; | ||||
|  |  | |||
|  | @ -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 \ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue