2017-04-27 18:30:36 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2015-06-04 10:29:50 +00:00
|
|
|
#include "qmlmanager.h"
|
2015-06-04 10:36:36 +00:00
|
|
|
#include <QUrl>
|
2018-09-04 17:02:26 +00:00
|
|
|
#include <QSettings>
|
2015-07-13 00:39:13 +00:00
|
|
|
#include <QDebug>
|
2015-12-05 03:34:59 +00:00
|
|
|
#include <QNetworkAccessManager>
|
|
|
|
#include <QAuthenticator>
|
2015-12-26 21:22:50 +00:00
|
|
|
#include <QDesktopServices>
|
2016-01-08 06:30:58 +00:00
|
|
|
#include <QTextDocument>
|
2016-03-11 02:36:46 +00:00
|
|
|
#include <QRegularExpression>
|
2016-04-03 23:13:22 +00:00
|
|
|
#include <QApplication>
|
|
|
|
#include <QElapsedTimer>
|
2016-06-13 22:21:51 +00:00
|
|
|
#include <QTimer>
|
2017-07-18 18:25:41 +00:00
|
|
|
#include <QDateTime>
|
2018-05-16 14:50:17 +00:00
|
|
|
#include <QClipboard>
|
2018-06-21 08:09:45 +00:00
|
|
|
#include <QFile>
|
2018-10-20 15:59:35 +00:00
|
|
|
#include <QtConcurrent>
|
|
|
|
#include <QFuture>
|
2017-10-16 01:43:38 +00:00
|
|
|
|
2017-10-12 07:43:40 +00:00
|
|
|
#include <QBluetoothLocalDevice>
|
2015-06-04 10:29:50 +00:00
|
|
|
|
2015-06-11 06:56:18 +00:00
|
|
|
#include "qt-models/divelistmodel.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "qt-models/gpslistmodel.h"
|
2018-01-28 08:52:51 +00:00
|
|
|
#include "qt-models/completionmodels.h"
|
2018-05-16 14:50:17 +00:00
|
|
|
#include "qt-models/messagehandlermodel.h"
|
2019-05-31 14:09:14 +00:00
|
|
|
#include "qt-models/tankinfomodel.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "core/device.h"
|
2019-08-05 17:41:15 +00:00
|
|
|
#include "core/errorhelper.h"
|
2019-03-03 21:29:40 +00:00
|
|
|
#include "core/file.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "core/qthelper.h"
|
|
|
|
#include "core/qt-gui.h"
|
|
|
|
#include "core/git-access.h"
|
|
|
|
#include "core/cloudstorage.h"
|
2016-04-29 13:28:09 +00:00
|
|
|
#include "core/membuffer.h"
|
2017-05-12 16:29:45 +00:00
|
|
|
#include "core/downloadfromdcthread.h"
|
2018-06-13 16:06:11 +00:00
|
|
|
#include "core/subsurface-string.h"
|
|
|
|
#include "core/pref.h"
|
2019-11-24 14:02:34 +00:00
|
|
|
#include "core/selection.h"
|
2018-05-28 14:25:39 +00:00
|
|
|
#include "core/ssrf.h"
|
2019-11-19 18:27:20 +00:00
|
|
|
#include "core/save-profiledata.h"
|
2019-12-09 18:58:20 +00:00
|
|
|
#include "core/settings/qPrefLog.h"
|
2018-09-08 17:46:11 +00:00
|
|
|
#include "core/settings/qPrefLocationService.h"
|
|
|
|
#include "core/settings/qPrefTechnicalDetails.h"
|
|
|
|
#include "core/settings/qPrefPartialPressureGas.h"
|
2018-09-16 19:34:39 +00:00
|
|
|
#include "core/settings/qPrefUnit.h"
|
2019-05-31 14:09:14 +00:00
|
|
|
#include "core/trip.h"
|
2019-12-14 20:56:31 +00:00
|
|
|
#include "backend-shared/exportfuncs.h"
|
2019-11-19 18:27:20 +00:00
|
|
|
#include "core/worldmap-save.h"
|
2019-11-30 19:16:49 +00:00
|
|
|
#include "core/uploadDiveLogsDE.h"
|
2019-12-08 10:52:38 +00:00
|
|
|
#include "core/uploadDiveShare.h"
|
2019-11-30 19:16:49 +00:00
|
|
|
|
2018-05-28 14:25:39 +00:00
|
|
|
|
2019-09-27 23:26:54 +00:00
|
|
|
QMLManager *QMLManager::m_instance = NULL;
|
2018-06-18 09:14:05 +00:00
|
|
|
bool noCloudToCloud = false;
|
2015-12-03 23:59:40 +00:00
|
|
|
|
2020-01-27 00:49:42 +00:00
|
|
|
#define RED_FONT QLatin1String("<font color=\"red\">")
|
|
|
|
#define END_FONT QLatin1String("</font>")
|
2016-03-11 05:59:16 +00:00
|
|
|
|
2018-01-26 09:40:04 +00:00
|
|
|
extern "C" void showErrorFromC(char *buf)
|
2018-01-24 21:56:52 +00:00
|
|
|
{
|
2018-01-26 09:40:04 +00:00
|
|
|
QString error(buf);
|
|
|
|
free(buf);
|
2018-01-24 21:56:52 +00:00
|
|
|
// By using invokeMethod with Qt:AutoConnection, the error string is safely
|
|
|
|
// transported across thread boundaries, if not called from the UI thread.
|
|
|
|
QMetaObject::invokeMethod(QMLManager::instance(), "registerError", Qt::AutoConnection, Q_ARG(QString, error));
|
|
|
|
}
|
|
|
|
|
2017-07-09 23:07:48 +00:00
|
|
|
static void progressCallback(const char *text)
|
|
|
|
{
|
|
|
|
QMLManager *self = QMLManager::instance();
|
|
|
|
if (self) {
|
|
|
|
self->appendTextToLog(QString(text));
|
|
|
|
self->setProgressMessage(QString(text));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-03 23:59:40 +00:00
|
|
|
static void appendTextToLogStandalone(const char *text)
|
2015-07-13 00:39:13 +00:00
|
|
|
{
|
2016-01-26 14:45:03 +00:00
|
|
|
QMLManager *self = QMLManager::instance();
|
|
|
|
if (self)
|
|
|
|
self->appendTextToLog(QString(text));
|
2015-07-13 00:39:13 +00:00
|
|
|
}
|
2015-06-09 19:20:44 +00:00
|
|
|
|
2017-06-18 06:22:37 +00:00
|
|
|
// show the git progress in the passive notification area
|
|
|
|
extern "C" int gitProgressCB(const char *text)
|
2015-12-15 07:00:19 +00:00
|
|
|
{
|
2016-04-03 23:13:22 +00:00
|
|
|
static QElapsedTimer timer;
|
2017-06-18 06:50:22 +00:00
|
|
|
static qint64 lastTime = 0;
|
2016-04-06 04:16:25 +00:00
|
|
|
static QMLManager *self;
|
|
|
|
|
|
|
|
if (!self)
|
|
|
|
self = QMLManager::instance();
|
2015-12-15 07:00:19 +00:00
|
|
|
|
2017-06-18 06:22:37 +00:00
|
|
|
if (!timer.isValid()) {
|
2016-04-03 23:13:22 +00:00
|
|
|
timer.restart();
|
|
|
|
lastTime = 0;
|
|
|
|
}
|
|
|
|
if (self) {
|
|
|
|
qint64 elapsed = timer.elapsed();
|
2017-06-18 06:22:37 +00:00
|
|
|
self->appendTextToLog(text);
|
|
|
|
self->setNotificationText(text);
|
2017-06-18 06:50:22 +00:00
|
|
|
if (elapsed - lastTime > 50) { // 20 Hz refresh
|
|
|
|
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
|
|
|
|
}
|
2016-04-03 23:13:22 +00:00
|
|
|
lastTime = elapsed;
|
2015-12-15 07:00:19 +00:00
|
|
|
}
|
|
|
|
// return 0 so that we don't end the download
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-12 09:55:26 +00:00
|
|
|
void QMLManager::registerError(QString error)
|
2018-01-24 21:56:52 +00:00
|
|
|
{
|
|
|
|
appendTextToLog(error);
|
|
|
|
if (!m_lastError.isEmpty())
|
|
|
|
m_lastError += '\n';
|
|
|
|
m_lastError += error;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QMLManager::consumeError()
|
|
|
|
{
|
|
|
|
QString ret;
|
|
|
|
ret.swap(m_lastError);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-12 07:43:40 +00:00
|
|
|
void QMLManager::btHostModeChange(QBluetoothLocalDevice::HostMode state)
|
|
|
|
{
|
|
|
|
BTDiscovery *btDiscovery = BTDiscovery::instance();
|
|
|
|
|
|
|
|
qDebug() << "btHostModeChange to " << state;
|
|
|
|
if (state != QBluetoothLocalDevice::HostPoweredOff) {
|
|
|
|
connectionListModel.removeAllAddresses();
|
|
|
|
btDiscovery->BTDiscoveryReDiscover();
|
|
|
|
m_btEnabled = btDiscovery->btAvailable();
|
|
|
|
} else {
|
|
|
|
connectionListModel.removeAllAddresses();
|
|
|
|
set_non_bt_addresses();
|
|
|
|
m_btEnabled = false;
|
|
|
|
}
|
|
|
|
emit btEnabledChanged();
|
|
|
|
}
|
|
|
|
|
2017-12-05 19:58:54 +00:00
|
|
|
void QMLManager::btRescan()
|
|
|
|
{
|
|
|
|
BTDiscovery::instance()->BTDiscoveryReDiscover();
|
|
|
|
}
|
|
|
|
|
2016-01-11 14:14:45 +00:00
|
|
|
QMLManager::QMLManager() : m_locationServiceEnabled(false),
|
2020-01-27 00:51:01 +00:00
|
|
|
m_verboseEnabled(false),
|
|
|
|
deletedDive(0),
|
|
|
|
deletedTrip(0),
|
|
|
|
m_updateSelectedDive(-1),
|
|
|
|
m_selectedDiveTimestamp(0),
|
|
|
|
alreadySaving(false),
|
|
|
|
m_pluggedInDeviceName(""),
|
|
|
|
m_showNonDiveComputers(false),
|
|
|
|
m_oldStatus(qPrefCloudStorage::CS_UNKNOWN)
|
2015-06-04 10:29:50 +00:00
|
|
|
{
|
2019-09-27 23:26:54 +00:00
|
|
|
m_instance = this;
|
2017-04-04 00:29:06 +00:00
|
|
|
m_lastDevicePixelRatio = qApp->devicePixelRatio();
|
2018-01-18 11:49:22 +00:00
|
|
|
timer.start();
|
QML UI: don't immediately save data after we make changes
Much as this felt like the prudent thing to do, it makes the UI painful
to use. In bad network conditions, with a large dive log, on a phone,
the save operation can take more than a minute - which is just completely
ludicrous.
So instead we mark the dive list changed when we make changes and wait
for the app to not be in the foreground. Once the OS tells us that we are
hidden (on the desktop that generally means we don't have focus, on a
mobile device it usually does mean that the app is not on the screen), we
check if there are data to be saved and do so.
There is of course a major problem with this logic. If the user switches
away from Subsurface-mobile but comes back fairly quickly (just reacting
to a notification or briefly checking something, changing a song,
something... then the app may still be non-responsive for quite a while.
So we need to do something about the time it takes us to save the git
tree locally, and then figure out if we can move at least some of the
network traffic to another thread.
And we need to make sure the user immediately notices that the app is not
crashed but is actually saving their data. But that's for another commit.
tl;dr: CAREFUL, don't kill Subsurface-mobile before it had time to save
your data or your changes may be gone. In typical use that shouldn't be
an issue, but it is something that we need to tell the user about.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-04 00:37:17 +00:00
|
|
|
connect(qobject_cast<QApplication *>(QApplication::instance()), &QApplication::applicationStateChanged, this, &QMLManager::applicationStateChanged);
|
2017-07-10 00:03:57 +00:00
|
|
|
|
2019-12-08 08:23:45 +00:00
|
|
|
// make upload signals available in QML
|
2019-12-27 12:26:05 +00:00
|
|
|
// Remark: signal - signal connect
|
2019-12-08 08:23:45 +00:00
|
|
|
connect(uploadDiveLogsDE::instance(), &uploadDiveLogsDE::uploadFinish,
|
2020-01-27 00:51:01 +00:00
|
|
|
this, &QMLManager::uploadFinish);
|
2019-12-08 08:23:45 +00:00
|
|
|
connect(uploadDiveLogsDE::instance(), &uploadDiveLogsDE::uploadProgress,
|
2020-01-27 00:51:01 +00:00
|
|
|
this, &QMLManager::uploadProgress);
|
2019-12-08 10:52:38 +00:00
|
|
|
connect(uploadDiveShare::instance(), &uploadDiveShare::uploadProgress,
|
2020-01-27 00:51:01 +00:00
|
|
|
this, &QMLManager::uploadProgress);
|
2019-12-08 10:52:38 +00:00
|
|
|
|
|
|
|
// uploadDiveShare::uploadFinish() is defined with 3 parameters,
|
2019-12-27 12:26:05 +00:00
|
|
|
// whereas QMLManager::uploadFinish() is defined with 2 parameters,
|
2019-12-08 10:52:38 +00:00
|
|
|
// Solution add a slot as landing zone.
|
2019-12-27 12:26:05 +00:00
|
|
|
connect(uploadDiveShare::instance(), &uploadDiveShare::uploadFinish,
|
2020-01-27 00:51:01 +00:00
|
|
|
this, &QMLManager::uploadFinishSlot);
|
2019-12-08 08:23:45 +00:00
|
|
|
|
2018-04-13 06:05:23 +00:00
|
|
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
2018-04-13 23:43:20 +00:00
|
|
|
#if defined(Q_OS_ANDROID)
|
2018-06-28 11:54:08 +00:00
|
|
|
// on Android we first try the GenericDataLocation (typically /storage/emulated/0) and if that fails
|
|
|
|
// (as happened e.g. on a Sony Xperia phone) we try several other default locations, with the TempLocation as last resort
|
|
|
|
QStringList fileLocations =
|
2020-01-27 00:51:01 +00:00
|
|
|
QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation) +
|
|
|
|
QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation) +
|
|
|
|
QStandardPaths::standardLocations(QStandardPaths::DownloadLocation) +
|
|
|
|
QStandardPaths::standardLocations(QStandardPaths::TempLocation);
|
2018-04-13 23:43:20 +00:00
|
|
|
#elif defined(Q_OS_IOS)
|
|
|
|
// on iOS we should save the data to the DocumentsLocation so it becomes accessible to the user
|
2018-06-28 11:54:08 +00:00
|
|
|
QStringList fileLocations =
|
2020-01-27 00:51:01 +00:00
|
|
|
QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
|
2018-04-13 23:43:20 +00:00
|
|
|
#endif
|
2018-06-28 11:54:08 +00:00
|
|
|
appLogFileOpen = false;
|
|
|
|
for (const QString &fileLocation : fileLocations) {
|
|
|
|
appLogFileName = fileLocation + "/subsurface.log";
|
|
|
|
appLogFile.setFileName(appLogFileName);
|
|
|
|
if (!appLogFile.open(QIODevice::ReadWrite|QIODevice::Truncate)) {
|
|
|
|
appendTextToLog("Failed to open logfile " + appLogFileName
|
2020-01-27 00:51:01 +00:00
|
|
|
+ " at " + QDateTime::currentDateTime().toString()
|
|
|
|
+ " error: " + appLogFile.errorString());
|
2018-06-28 11:54:08 +00:00
|
|
|
} else {
|
|
|
|
// found a directory that works
|
|
|
|
appLogFileOpen = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (appLogFileOpen) {
|
2017-07-18 18:25:41 +00:00
|
|
|
appendTextToLog("Successfully opened logfile " + appLogFileName
|
2020-01-27 00:51:01 +00:00
|
|
|
+ " at " + QDateTime::currentDateTime().toString());
|
2018-06-28 11:54:08 +00:00
|
|
|
// if we were able to write the overall logfile, also write the libdivecomputer logfile
|
|
|
|
QString libdcLogFileName = appLogFileName.replace("/subsurface.log", "/libdivecomputer.log");
|
|
|
|
// remove the existing libdivecomputer logfile so we don't copy an old one by mistake
|
|
|
|
QFile libdcLog(libdcLogFileName);
|
|
|
|
libdcLog.remove();
|
|
|
|
logfile_name = copy_qstring(libdcLogFileName);
|
|
|
|
} else {
|
|
|
|
appendTextToLog("No writeable location found, in-memory log only and no libdivecomputer log");
|
2017-07-10 00:03:57 +00:00
|
|
|
}
|
|
|
|
#endif
|
2018-01-24 21:56:52 +00:00
|
|
|
set_error_cb(&showErrorFromC);
|
2017-06-18 06:23:41 +00:00
|
|
|
appendTextToLog("Starting " + getUserAgent());
|
2017-11-27 18:11:52 +00:00
|
|
|
appendTextToLog(QStringLiteral("built with libdivecomputer v%1").arg(dc_version(NULL)));
|
|
|
|
appendTextToLog(QStringLiteral("built with Qt Version %1, runtime from Qt Version %2").arg(QT_VERSION_STR).arg(qVersion()));
|
|
|
|
int git_maj, git_min, git_rev;
|
|
|
|
git_libgit2_version(&git_maj, &git_min, &git_rev);
|
|
|
|
appendTextToLog(QStringLiteral("built with libgit2 %1.%2.%3").arg(git_maj).arg(git_min).arg(git_rev));
|
2019-09-18 20:13:00 +00:00
|
|
|
appendTextToLog(QStringLiteral("Running on %1").arg(QSysInfo::prettyProductName()));
|
2019-09-18 20:35:22 +00:00
|
|
|
#if defined(Q_OS_ANDROID)
|
|
|
|
extern QString getAndroidHWInfo();
|
|
|
|
appendTextToLog(getAndroidHWInfo());
|
|
|
|
#endif
|
2016-02-11 01:31:52 +00:00
|
|
|
setStartPageText(tr("Starting..."));
|
2020-01-12 04:59:08 +00:00
|
|
|
if (ignore_bt) {
|
|
|
|
m_btEnabled = false;
|
|
|
|
} else {
|
|
|
|
// ensure that we start the BTDiscovery - this should be triggered by the export of the class
|
|
|
|
// to QML, but that doesn't seem to always work
|
|
|
|
BTDiscovery *btDiscovery = BTDiscovery::instance();
|
|
|
|
m_btEnabled = btDiscovery->btAvailable();
|
|
|
|
connect(&btDiscovery->localBtDevice, &QBluetoothLocalDevice::hostModeStateChanged,
|
|
|
|
this, &QMLManager::btHostModeChange);
|
|
|
|
}
|
2015-11-11 20:32:54 +00:00
|
|
|
// create location manager service
|
2015-12-03 23:59:40 +00:00
|
|
|
locationProvider = new GpsLocation(&appendTextToLogStandalone, this);
|
2017-07-09 23:07:48 +00:00
|
|
|
progress_callback = &progressCallback;
|
2016-04-18 05:54:53 +00:00
|
|
|
connect(locationProvider, SIGNAL(haveSourceChanged()), this, SLOT(hasLocationSourceChanged()));
|
|
|
|
setLocationServiceAvailable(locationProvider->hasLocationsSource());
|
2015-12-15 07:00:19 +00:00
|
|
|
set_git_update_cb(&gitProgressCB);
|
2016-02-08 19:08:49 +00:00
|
|
|
|
2019-03-12 16:28:43 +00:00
|
|
|
// present dive site lists sorted by name
|
|
|
|
locationModel.sort(LocationInformationModel::NAME);
|
|
|
|
|
2016-02-08 19:08:49 +00:00
|
|
|
// make sure we know if the current cloud repo has been successfully synced
|
|
|
|
syncLoadFromCloud();
|
2018-11-18 06:12:09 +00:00
|
|
|
|
|
|
|
memset(&m_copyPasteDive, 0, sizeof(m_copyPasteDive));
|
|
|
|
memset(&what, 0, sizeof(what));
|
|
|
|
|
|
|
|
// Let's set some defaults to be copied so users don't necessarily need
|
|
|
|
// to know how to configure this
|
|
|
|
what.divemaster = true;
|
|
|
|
what.buddy = true;
|
|
|
|
what.suit = true;
|
|
|
|
what.tags = true;
|
|
|
|
what.cylinders = true;
|
|
|
|
what.weights = true;
|
2020-02-18 01:16:11 +00:00
|
|
|
|
|
|
|
// monitor when dives changed - but only in verbose mode
|
|
|
|
// careful - changing verbose at runtime isn't enough (of course that could be added if we want it)
|
|
|
|
if (verbose)
|
|
|
|
connect(&diveListNotifier, &DiveListNotifier::divesChanged, this, &QMLManager::divesChanged);
|
2015-12-05 03:34:59 +00:00
|
|
|
}
|
2015-11-11 20:32:54 +00:00
|
|
|
|
QML UI: don't immediately save data after we make changes
Much as this felt like the prudent thing to do, it makes the UI painful
to use. In bad network conditions, with a large dive log, on a phone,
the save operation can take more than a minute - which is just completely
ludicrous.
So instead we mark the dive list changed when we make changes and wait
for the app to not be in the foreground. Once the OS tells us that we are
hidden (on the desktop that generally means we don't have focus, on a
mobile device it usually does mean that the app is not on the screen), we
check if there are data to be saved and do so.
There is of course a major problem with this logic. If the user switches
away from Subsurface-mobile but comes back fairly quickly (just reacting
to a notification or briefly checking something, changing a song,
something... then the app may still be non-responsive for quite a while.
So we need to do something about the time it takes us to save the git
tree locally, and then figure out if we can move at least some of the
network traffic to another thread.
And we need to make sure the user immediately notices that the app is not
crashed but is actually saving their data. But that's for another commit.
tl;dr: CAREFUL, don't kill Subsurface-mobile before it had time to save
your data or your changes may be gone. In typical use that shouldn't be
an issue, but it is something that we need to tell the user about.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-04 00:37:17 +00:00
|
|
|
void QMLManager::applicationStateChanged(Qt::ApplicationState state)
|
|
|
|
{
|
|
|
|
QString stateText;
|
|
|
|
switch (state) {
|
|
|
|
case Qt::ApplicationActive: stateText = "active"; break;
|
|
|
|
case Qt::ApplicationHidden: stateText = "hidden"; break;
|
|
|
|
case Qt::ApplicationSuspended: stateText = "suspended"; break;
|
|
|
|
case Qt::ApplicationInactive: stateText = "inactive"; break;
|
|
|
|
default: stateText = QString("none of the four: 0x") + QString::number(state, 16);
|
|
|
|
}
|
2016-04-18 13:15:54 +00:00
|
|
|
stateText.prepend("AppState changed to ");
|
QML UI: don't immediately save data after we make changes
Much as this felt like the prudent thing to do, it makes the UI painful
to use. In bad network conditions, with a large dive log, on a phone,
the save operation can take more than a minute - which is just completely
ludicrous.
So instead we mark the dive list changed when we make changes and wait
for the app to not be in the foreground. Once the OS tells us that we are
hidden (on the desktop that generally means we don't have focus, on a
mobile device it usually does mean that the app is not on the screen), we
check if there are data to be saved and do so.
There is of course a major problem with this logic. If the user switches
away from Subsurface-mobile but comes back fairly quickly (just reacting
to a notification or briefly checking something, changing a song,
something... then the app may still be non-responsive for quite a while.
So we need to do something about the time it takes us to save the git
tree locally, and then figure out if we can move at least some of the
network traffic to another thread.
And we need to make sure the user immediately notices that the app is not
crashed but is actually saving their data. But that's for another commit.
tl;dr: CAREFUL, don't kill Subsurface-mobile before it had time to save
your data or your changes may be gone. In typical use that shouldn't be
an issue, but it is something that we need to tell the user about.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-04 00:37:17 +00:00
|
|
|
stateText.append(" with ");
|
2020-01-27 00:49:42 +00:00
|
|
|
stateText.append((alreadySaving ? QLatin1String("") : QLatin1String("no ")) + QLatin1String("save ongoing"));
|
2016-04-04 17:57:44 +00:00
|
|
|
stateText.append(" and ");
|
2020-01-27 00:49:42 +00:00
|
|
|
stateText.append((unsaved_changes() ? QLatin1String("") : QLatin1String("no ")) + QLatin1String("unsaved changes"));
|
QML UI: don't immediately save data after we make changes
Much as this felt like the prudent thing to do, it makes the UI painful
to use. In bad network conditions, with a large dive log, on a phone,
the save operation can take more than a minute - which is just completely
ludicrous.
So instead we mark the dive list changed when we make changes and wait
for the app to not be in the foreground. Once the OS tells us that we are
hidden (on the desktop that generally means we don't have focus, on a
mobile device it usually does mean that the app is not on the screen), we
check if there are data to be saved and do so.
There is of course a major problem with this logic. If the user switches
away from Subsurface-mobile but comes back fairly quickly (just reacting
to a notification or briefly checking something, changing a song,
something... then the app may still be non-responsive for quite a while.
So we need to do something about the time it takes us to save the git
tree locally, and then figure out if we can move at least some of the
network traffic to another thread.
And we need to make sure the user immediately notices that the app is not
crashed but is actually saving their data. But that's for another commit.
tl;dr: CAREFUL, don't kill Subsurface-mobile before it had time to save
your data or your changes may be gone. In typical use that shouldn't be
an issue, but it is something that we need to tell the user about.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-04 00:37:17 +00:00
|
|
|
appendTextToLog(stateText);
|
|
|
|
|
|
|
|
if (!alreadySaving && state == Qt::ApplicationInactive && unsaved_changes()) {
|
|
|
|
// FIXME
|
|
|
|
// make sure the user sees that we are saving data if they come back
|
|
|
|
// while this is running
|
2016-04-08 19:35:45 +00:00
|
|
|
saveChangesCloud(false);
|
2018-01-18 11:46:29 +00:00
|
|
|
appendTextToLog("done saving to git local / remote");
|
QML UI: don't immediately save data after we make changes
Much as this felt like the prudent thing to do, it makes the UI painful
to use. In bad network conditions, with a large dive log, on a phone,
the save operation can take more than a minute - which is just completely
ludicrous.
So instead we mark the dive list changed when we make changes and wait
for the app to not be in the foreground. Once the OS tells us that we are
hidden (on the desktop that generally means we don't have focus, on a
mobile device it usually does mean that the app is not on the screen), we
check if there are data to be saved and do so.
There is of course a major problem with this logic. If the user switches
away from Subsurface-mobile but comes back fairly quickly (just reacting
to a notification or briefly checking something, changing a song,
something... then the app may still be non-responsive for quite a while.
So we need to do something about the time it takes us to save the git
tree locally, and then figure out if we can move at least some of the
network traffic to another thread.
And we need to make sure the user immediately notices that the app is not
crashed but is actually saving their data. But that's for another commit.
tl;dr: CAREFUL, don't kill Subsurface-mobile before it had time to save
your data or your changes may be gone. In typical use that shouldn't be
an issue, but it is something that we need to tell the user about.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-04 00:37:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-09 15:53:22 +00:00
|
|
|
void QMLManager::openLocalThenRemote(QString url)
|
|
|
|
{
|
2019-11-06 06:10:03 +00:00
|
|
|
CollapsedDiveListSortModel::instance()->setSourceModel(nullptr);
|
2019-09-26 11:37:44 +00:00
|
|
|
DiveListModel::instance()->clear();
|
2017-06-18 06:22:37 +00:00
|
|
|
setNotificationText(tr("Open local dive data file"));
|
2016-02-09 15:53:22 +00:00
|
|
|
QByteArray fileNamePrt = QFile::encodeName(url);
|
2019-11-03 13:05:05 +00:00
|
|
|
/* if this is a cloud storage repo and we have no local cache (i.e., it's the first time
|
|
|
|
* we try to open this), parse_file will ALWAYS connect to the remote and populate the cache.
|
|
|
|
* Otherwise parse_file will respect the git_local_only flag and only update if that isn't set */
|
2019-02-28 21:45:17 +00:00
|
|
|
int error = parse_file(fileNamePrt.data(), &dive_table, &trip_table, &dive_site_table);
|
2016-02-09 15:53:22 +00:00
|
|
|
if (error) {
|
2016-03-13 15:58:57 +00:00
|
|
|
appendTextToLog(QStringLiteral("loading dives from cache failed %1").arg(error));
|
2017-06-18 06:22:37 +00:00
|
|
|
setNotificationText(tr("Opening local data file failed"));
|
2017-10-17 11:28:36 +00:00
|
|
|
/* there can be 2 reasons for this:
|
|
|
|
* 1) we have cloud credentials, but there is no local repo (yet).
|
|
|
|
* This implies that the PIN verify is still to be done.
|
|
|
|
* 2) we are in a very clean state after installing the app, and
|
|
|
|
* want to use a NO CLOUD setup. The intial repo has no initial
|
|
|
|
* commit in it, so its master branch does not yet exist. We do not
|
|
|
|
* care about this, as the very first commit of dive data to the
|
|
|
|
* no cloud repo solves this.
|
|
|
|
*/
|
2019-12-28 16:30:14 +00:00
|
|
|
auto credStatus = qPrefCloudStorage::cloud_verification_status();
|
2019-09-10 10:26:09 +00:00
|
|
|
if (credStatus != qPrefCloudStorage::CS_NOCLOUD &&
|
|
|
|
credStatus != qPrefCloudStorage::CS_INCORRECT_USER_PASSWD)
|
2019-12-28 17:18:06 +00:00
|
|
|
qPrefCloudStorage::set_cloud_verification_status(qPrefCloudStorage::CS_NEED_TO_VERIFY);
|
2016-02-09 15:53:22 +00:00
|
|
|
} else {
|
mobile: remove superfluous state VALID_EMAIL
This is a no-brainer removal of the VALID_EMAIL state used in QMLManager.
All current usage of this state is "if state is VALID or VALID_EMAIL",
so there is no distinction between the two states.
It is even a little different. The comment suggests "when we can open
a local cloud storage, tied to a cloud account (so explicitly not
the no-cloud status), we have at least a valid email". While this
is formally true, this implies that there is also a cloud account
on the cloud server (ie. the cloud account is in a VERIFIED state).
In other words: currently, there can't exist a valid local storage
that is tied to a valid email adress, without valid cloud account
on the server.
Notice that this touches the discussion on GitHub for commit
e76f527fe530636 (pull request #520). Can we implement the creation
of a valid cloud account without data link to the cloud server?
Currently, we need the server to confirm the email address (for
example for uniqueness reasons on server side). Obviously, we could
hack our way out of this, but we have a perfect solution already
in place. Create a no-cloud account, and transfer that later to
a true and valid cloud account.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2017-08-01 09:38:59 +00:00
|
|
|
// if we can load from the cache, we know that we have a valid cloud account
|
2019-11-03 13:06:10 +00:00
|
|
|
// and we know that there was at least one successful sync with the cloud when
|
|
|
|
// that local cache was created - so there is a common ancestor
|
|
|
|
setLoadFromCloud(true);
|
2019-12-28 16:30:14 +00:00
|
|
|
if (qPrefCloudStorage::cloud_verification_status() == qPrefCloudStorage::CS_UNKNOWN)
|
2019-12-28 17:18:06 +00:00
|
|
|
qPrefCloudStorage::set_cloud_verification_status(qPrefCloudStorage::CS_VERIFIED);
|
2020-01-07 13:31:49 +00:00
|
|
|
qPrefUnits::set_unit_system(git_prefs.unit_system);
|
2018-08-15 09:53:49 +00:00
|
|
|
qPrefTechnicalDetails::set_tankbar(git_prefs.tankbar);
|
|
|
|
qPrefTechnicalDetails::set_dcceiling(git_prefs.dcceiling);
|
|
|
|
qPrefTechnicalDetails::set_show_ccr_setpoint(git_prefs.show_ccr_setpoint);
|
|
|
|
qPrefTechnicalDetails::set_show_ccr_sensors(git_prefs.show_ccr_sensors);
|
|
|
|
qPrefPartialPressureGas::set_po2(git_prefs.pp_graphs.po2);
|
2018-09-23 10:53:35 +00:00
|
|
|
process_loaded_dives();
|
2019-08-14 16:09:17 +00:00
|
|
|
DiveListModel::instance()->reload();
|
2019-11-06 06:10:03 +00:00
|
|
|
CollapsedDiveListSortModel::instance()->setSourceModel(DiveListModel::instance());
|
|
|
|
CollapsedDiveListSortModel::instance()->updateFilterState();
|
2016-04-06 04:17:37 +00:00
|
|
|
appendTextToLog(QStringLiteral("%1 dives loaded from cache").arg(dive_table.nr));
|
2017-06-18 06:22:37 +00:00
|
|
|
setNotificationText(tr("%1 dives loaded from local dive data file").arg(dive_table.nr));
|
2016-02-09 15:53:22 +00:00
|
|
|
}
|
2019-12-28 16:30:14 +00:00
|
|
|
if (qPrefCloudStorage::cloud_verification_status() == qPrefCloudStorage::CS_NEED_TO_VERIFY) {
|
2017-09-27 15:08:30 +00:00
|
|
|
appendTextToLog(QStringLiteral("have cloud credentials, but still needs PIN"));
|
|
|
|
}
|
2019-12-28 16:30:14 +00:00
|
|
|
if (qPrefCloudStorage::cloud_verification_status() == qPrefCloudStorage::CS_INCORRECT_USER_PASSWD) {
|
2019-09-10 10:26:09 +00:00
|
|
|
appendTextToLog(QStringLiteral("incorrect password for cloud credentials"));
|
|
|
|
setNotificationText(tr("Incorrect cloud credentials"));
|
|
|
|
}
|
2019-12-29 11:33:30 +00:00
|
|
|
if (m_oldStatus == qPrefCloudStorage::CS_NOCLOUD) {
|
2017-08-03 12:55:09 +00:00
|
|
|
// if we switch to credentials from CS_NOCLOUD, we take things online temporarily
|
2018-09-10 13:30:01 +00:00
|
|
|
git_local_only = false;
|
2016-04-29 13:28:09 +00:00
|
|
|
appendTextToLog(QStringLiteral("taking things online to be able to switch to cloud account"));
|
|
|
|
}
|
2017-12-10 21:22:13 +00:00
|
|
|
set_filename(fileNamePrt.data());
|
2018-09-10 13:30:01 +00:00
|
|
|
if (git_local_only) {
|
2016-04-08 19:35:45 +00:00
|
|
|
appendTextToLog(QStringLiteral("have cloud credentials, but user asked not to connect to network"));
|
2016-04-14 12:42:08 +00:00
|
|
|
alreadySaving = false;
|
2016-04-08 19:35:45 +00:00
|
|
|
} else {
|
|
|
|
appendTextToLog(QStringLiteral("have cloud credentials, trying to connect"));
|
|
|
|
tryRetrieveDataFromBackend();
|
|
|
|
}
|
2018-01-28 16:39:01 +00:00
|
|
|
updateAllGlobalLists();
|
|
|
|
}
|
|
|
|
|
2019-08-10 15:41:35 +00:00
|
|
|
void QMLManager::updateSiteList()
|
|
|
|
{
|
|
|
|
LocationInformationModel::instance()->update();
|
|
|
|
emit locationListChanged();
|
|
|
|
}
|
|
|
|
|
2018-01-28 16:39:01 +00:00
|
|
|
void QMLManager::updateAllGlobalLists()
|
|
|
|
{
|
2018-01-28 09:26:45 +00:00
|
|
|
buddyModel.updateModel(); emit buddyListChanged();
|
2018-01-28 08:52:51 +00:00
|
|
|
suitModel.updateModel(); emit suitListChanged();
|
2018-01-28 10:28:01 +00:00
|
|
|
divemasterModel.updateModel(); emit divemasterListChanged();
|
2019-03-12 16:28:43 +00:00
|
|
|
// TODO: Probably not needed anymore, as the dive site list is generated on the fly!
|
2019-08-10 15:41:35 +00:00
|
|
|
updateSiteList();
|
2016-02-09 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
2016-04-29 13:28:09 +00:00
|
|
|
void QMLManager::mergeLocalRepo()
|
|
|
|
{
|
2016-04-30 13:51:26 +00:00
|
|
|
char *filename = NOCLOUD_LOCALSTORAGE;
|
2020-01-09 05:25:02 +00:00
|
|
|
struct dive_table table = empty_dive_table;
|
|
|
|
struct trip_table trips = empty_trip_table;
|
|
|
|
struct dive_site_table sites = empty_dive_site_table;
|
2019-03-03 14:12:22 +00:00
|
|
|
parse_file(filename, &table, &trips, &sites);
|
|
|
|
add_imported_dives(&table, &trips, &sites, IMPORT_MERGE_ALL_TRIPS);
|
2016-04-29 13:28:09 +00:00
|
|
|
}
|
|
|
|
|
2018-05-16 14:50:17 +00:00
|
|
|
void QMLManager::copyAppLogToClipboard()
|
|
|
|
{
|
2019-11-09 18:14:15 +00:00
|
|
|
// The About page offers a button to copy logs so they can be pasted elsewhere
|
|
|
|
QApplication::clipboard()->setText(getCombinedLogs(), QClipboard::Clipboard);
|
|
|
|
}
|
2018-05-21 08:55:07 +00:00
|
|
|
|
2019-11-09 18:14:15 +00:00
|
|
|
bool QMLManager::createSupportEmail()
|
|
|
|
{
|
|
|
|
QString mailToLink = "mailto:in-app-support@subsurface-divelog.org?subject=Subsurface-mobile support request";
|
|
|
|
mailToLink += "&body=Please describe your issue here and keep the logs below:\n\n\n\n";
|
|
|
|
mailToLink += getCombinedLogs();
|
|
|
|
if (QDesktopServices::openUrl(QUrl(mailToLink))) {
|
|
|
|
appendTextToLog("OS accepted support email");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
appendTextToLog("failed to create support email");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// useful for support requests
|
|
|
|
QString QMLManager::getCombinedLogs()
|
|
|
|
{
|
2018-05-21 08:55:07 +00:00
|
|
|
// Add heading and append subsurface.log
|
2019-11-09 18:14:15 +00:00
|
|
|
QString copyString = "\n---------- subsurface.log ----------\n";
|
2018-05-21 08:55:07 +00:00
|
|
|
copyString += MessageHandlerModel::self()->logAsString();
|
|
|
|
|
|
|
|
// Add heading and append libdivecomputer.log
|
|
|
|
QFile f(logfile_name);
|
|
|
|
if (f.open(QFile::ReadOnly | QFile::Text)) {
|
|
|
|
copyString += "\n\n\n---------- libdivecomputer.log ----------\n";
|
|
|
|
|
|
|
|
QTextStream in(&f);
|
|
|
|
copyString += in.readAll();
|
|
|
|
}
|
2018-06-28 13:42:13 +00:00
|
|
|
|
2018-05-21 08:55:07 +00:00
|
|
|
copyString += "---------- finish ----------\n";
|
|
|
|
|
2018-06-28 13:42:13 +00:00
|
|
|
#if defined(Q_OS_ANDROID)
|
|
|
|
// on Android, the clipboard is effectively limited in size, but there is no
|
|
|
|
// predefined hard limit. All remote procedure calls use a shared Binder
|
|
|
|
// transaction buffer that is limited to 1MB. To work around this let's truncate
|
|
|
|
// the log once it is more than half a million characters. Qt doesn't tell us if
|
|
|
|
// the clipboard transaction fails, hopefully this will typically leave enough
|
|
|
|
// margin of error.
|
|
|
|
if (copyString.size() > 500000) {
|
|
|
|
copyString.truncate(500000);
|
|
|
|
copyString += "\n\n---------- truncated ----------\n";
|
|
|
|
}
|
|
|
|
#endif
|
2019-11-09 18:14:15 +00:00
|
|
|
return copyString;
|
2018-05-16 14:50:17 +00:00
|
|
|
}
|
|
|
|
|
2015-12-05 03:34:59 +00:00
|
|
|
void QMLManager::finishSetup()
|
|
|
|
{
|
2015-11-11 20:32:54 +00:00
|
|
|
// Initialize cloud credentials.
|
2018-10-09 08:23:24 +00:00
|
|
|
git_local_only = !prefs.cloud_auto_sync;
|
2019-12-28 17:37:46 +00:00
|
|
|
|
2015-11-18 21:14:19 +00:00
|
|
|
// if the cloud credentials are valid, we should get the GPS Webservice ID as well
|
2015-12-27 16:32:15 +00:00
|
|
|
QString url;
|
2019-12-20 15:35:12 +00:00
|
|
|
if (!qPrefCloudStorage::cloud_storage_email().isEmpty() &&
|
2019-12-20 16:04:28 +00:00
|
|
|
!qPrefCloudStorage::cloud_storage_password().isEmpty() &&
|
2015-12-27 16:32:15 +00:00
|
|
|
getCloudURL(url) == 0) {
|
2016-04-06 18:47:12 +00:00
|
|
|
// we know that we are the first ones to access git storage, so we don't need to test,
|
|
|
|
// but we need to make sure we stay the only ones accessing git storage
|
|
|
|
alreadySaving = true;
|
2016-02-09 15:53:22 +00:00
|
|
|
openLocalThenRemote(url);
|
2018-06-13 16:06:11 +00:00
|
|
|
} else if (!empty_string(existing_filename) &&
|
2020-01-27 00:51:01 +00:00
|
|
|
qPrefCloudStorage::cloud_verification_status() != qPrefCloudStorage::CS_UNKNOWN) {
|
2019-12-29 11:33:30 +00:00
|
|
|
setOldStatus((qPrefCloudStorage::cloud_status)qPrefCloudStorage::cloud_verification_status());
|
2019-12-28 17:42:04 +00:00
|
|
|
set_filename(NOCLOUD_LOCALSTORAGE);
|
|
|
|
qPrefCloudStorage::set_cloud_verification_status(qPrefCloudStorage::CS_NOCLOUD);
|
2019-12-27 12:56:33 +00:00
|
|
|
saveCloudCredentials(qPrefCloudStorage::cloud_storage_email(), qPrefCloudStorage::cloud_storage_password(), qPrefCloudStorage::cloud_storage_pin());
|
2016-04-22 14:13:14 +00:00
|
|
|
appendTextToLog(tr("working in no-cloud mode"));
|
2019-02-28 21:45:17 +00:00
|
|
|
int error = parse_file(existing_filename, &dive_table, &trip_table, &dive_site_table);
|
2016-04-27 13:14:13 +00:00
|
|
|
if (error) {
|
|
|
|
// we got an error loading the local file
|
2017-06-18 06:22:37 +00:00
|
|
|
setNotificationText(tr("Error parsing local storage, giving up"));
|
2017-12-10 21:22:13 +00:00
|
|
|
set_filename(NULL);
|
2016-04-27 13:14:13 +00:00
|
|
|
} else {
|
|
|
|
// successfully opened the local file, now add thigs to the dive list
|
|
|
|
consumeFinishedLoad(0);
|
|
|
|
appendTextToLog(QString("working in no-cloud mode, finished loading %1 dives from %2").arg(dive_table.nr).arg(existing_filename));
|
|
|
|
}
|
2015-12-20 00:08:10 +00:00
|
|
|
} else {
|
2019-12-28 17:18:06 +00:00
|
|
|
qPrefCloudStorage::set_cloud_verification_status(qPrefCloudStorage::CS_UNKNOWN);
|
2016-04-22 14:13:14 +00:00
|
|
|
appendTextToLog(tr("no cloud credentials"));
|
2016-03-11 05:59:16 +00:00
|
|
|
setStartPageText(RED_FONT + tr("Please enter valid cloud credentials.") + END_FONT);
|
2015-12-20 00:08:10 +00:00
|
|
|
}
|
2015-06-04 10:29:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QMLManager::~QMLManager()
|
|
|
|
{
|
2018-04-13 23:53:51 +00:00
|
|
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
2017-07-10 00:03:57 +00:00
|
|
|
if (appLogFileOpen)
|
|
|
|
appLogFile.close();
|
|
|
|
#endif
|
2019-09-27 23:26:54 +00:00
|
|
|
m_instance = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
QMLManager *QMLManager::instance()
|
|
|
|
{
|
|
|
|
return m_instance;
|
2015-06-04 10:29:50 +00:00
|
|
|
}
|
|
|
|
|
2015-12-05 03:34:59 +00:00
|
|
|
#define CLOUDURL QString(prefs.cloud_base_url)
|
|
|
|
#define CLOUDREDIRECTURL CLOUDURL + "/cgi-bin/redirect.pl"
|
|
|
|
|
2019-12-27 12:56:33 +00:00
|
|
|
void QMLManager::saveCloudCredentials(const QString &newEmail, const QString &newPassword, const QString &pin)
|
2015-12-03 22:30:30 +00:00
|
|
|
{
|
|
|
|
bool cloudCredentialsChanged = false;
|
2019-12-28 16:30:14 +00:00
|
|
|
bool noCloud = qPrefCloudStorage::cloud_verification_status() == qPrefCloudStorage::CS_NOCLOUD;
|
2019-09-10 10:24:06 +00:00
|
|
|
|
2017-07-15 05:15:31 +00:00
|
|
|
// make sure we only have letters, numbers, and +-_. in password and email address
|
|
|
|
QRegularExpression regExp("^[a-zA-Z0-9@.+_-]+$");
|
2019-09-10 10:24:06 +00:00
|
|
|
if (!noCloud) {
|
2017-09-27 16:19:53 +00:00
|
|
|
// in case of NO_CLOUD, the email address + passwd do not care, so do not check it.
|
2019-12-20 16:04:28 +00:00
|
|
|
if (newPassword.isEmpty() ||
|
2020-01-27 00:51:01 +00:00
|
|
|
!regExp.match(newPassword).hasMatch() ||
|
|
|
|
!regExp.match(newEmail).hasMatch()) {
|
2017-09-27 16:19:53 +00:00
|
|
|
setStartPageText(RED_FONT + tr("Cloud storage email and password can only consist of letters, numbers, and '.', '-', '_', and '+'.") + END_FONT);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// use the same simplistic regex as the backend to check email addresses
|
|
|
|
regExp = QRegularExpression("^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9.+_-]+\\.[a-zA-Z0-9]+");
|
2019-12-20 15:35:12 +00:00
|
|
|
if (!regExp.match(newEmail).hasMatch()) {
|
2017-09-27 16:19:53 +00:00
|
|
|
setStartPageText(RED_FONT + tr("Invalid format for email address") + END_FONT);
|
|
|
|
return;
|
|
|
|
}
|
2017-07-15 05:15:31 +00:00
|
|
|
}
|
2019-12-20 15:35:12 +00:00
|
|
|
if (!same_string(prefs.cloud_storage_email, qPrintable(newEmail))) {
|
2015-11-18 21:14:19 +00:00
|
|
|
cloudCredentialsChanged = true;
|
2015-07-13 00:39:13 +00:00
|
|
|
}
|
2015-11-18 21:14:19 +00:00
|
|
|
|
2019-12-20 16:04:28 +00:00
|
|
|
if (!same_string(prefs.cloud_storage_password, qPrintable(newPassword))) {
|
|
|
|
cloudCredentialsChanged = true;
|
|
|
|
}
|
2015-11-18 21:14:19 +00:00
|
|
|
|
2019-12-28 16:30:14 +00:00
|
|
|
if (qPrefCloudStorage::cloud_verification_status() != qPrefCloudStorage::CS_NOCLOUD &&
|
2020-01-27 00:51:01 +00:00
|
|
|
!cloudCredentialsChanged) {
|
2016-04-06 18:42:38 +00:00
|
|
|
// just go back to the dive list
|
2019-12-29 11:33:30 +00:00
|
|
|
qPrefCloudStorage::set_cloud_verification_status(m_oldStatus);
|
2016-04-06 18:42:38 +00:00
|
|
|
}
|
2016-04-29 13:24:21 +00:00
|
|
|
|
2019-09-10 10:24:06 +00:00
|
|
|
if (!noCloud &&
|
2020-01-27 00:51:01 +00:00
|
|
|
!verifyCredentials(newEmail, newPassword, pin))
|
2019-09-10 10:24:06 +00:00
|
|
|
return;
|
|
|
|
|
2019-12-20 15:35:12 +00:00
|
|
|
qPrefCloudStorage::set_cloud_storage_email(newEmail);
|
2019-12-20 16:04:28 +00:00
|
|
|
qPrefCloudStorage::set_cloud_storage_password(newPassword);
|
2019-09-10 10:24:06 +00:00
|
|
|
|
|
|
|
if (noCloud && cloudCredentialsChanged && dive_table.nr) {
|
2018-06-18 09:14:05 +00:00
|
|
|
// we came from NOCLOUD and are connecting to a cloud account;
|
|
|
|
// since we already have dives in the table, let's remember that so we can keep them
|
|
|
|
noCloudToCloud = true;
|
|
|
|
appendTextToLog("transitioning from no-cloud to cloud and have dives");
|
|
|
|
}
|
2019-12-20 15:35:12 +00:00
|
|
|
if (qPrefCloudStorage::cloud_storage_email().isEmpty() ||
|
2020-01-27 00:51:01 +00:00
|
|
|
qPrefCloudStorage::cloud_storage_password().isEmpty()) {
|
2016-03-11 05:59:16 +00:00
|
|
|
setStartPageText(RED_FONT + tr("Please enter valid cloud credentials.") + END_FONT);
|
2016-02-13 06:06:38 +00:00
|
|
|
} else if (cloudCredentialsChanged) {
|
2016-04-29 12:04:47 +00:00
|
|
|
// let's make sure there are no unsaved changes
|
|
|
|
saveChangesLocal();
|
2016-02-08 19:14:11 +00:00
|
|
|
syncLoadFromCloud();
|
2016-02-09 15:53:22 +00:00
|
|
|
QString url;
|
|
|
|
getCloudURL(url);
|
2016-02-11 02:14:09 +00:00
|
|
|
manager()->clearAccessCache(); // remove any chached credentials
|
2016-02-11 05:24:10 +00:00
|
|
|
clear_git_id(); // invalidate our remembered GIT SHA
|
2019-08-14 16:09:17 +00:00
|
|
|
DiveListModel::instance()->reload();
|
2016-02-12 06:46:35 +00:00
|
|
|
GpsListModel::instance()->clear();
|
2016-02-12 14:54:52 +00:00
|
|
|
setStartPageText(tr("Attempting to open cloud storage with new credentials"));
|
2016-04-06 18:47:12 +00:00
|
|
|
// we therefore know that no one else is already accessing THIS git repo;
|
|
|
|
// let's make sure we stay the only ones doing so
|
|
|
|
alreadySaving = true;
|
2016-04-30 18:08:33 +00:00
|
|
|
// since we changed credentials, we need to try to connect to the cloud, regardless
|
|
|
|
// of whether we're in offline mode or not, to make sure the repository is synced
|
2018-09-10 13:30:01 +00:00
|
|
|
currentGitLocalOnly = git_local_only;
|
|
|
|
git_local_only = false;
|
2016-02-09 15:53:22 +00:00
|
|
|
openLocalThenRemote(url);
|
2015-12-05 03:34:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-10 10:19:36 +00:00
|
|
|
bool QMLManager::verifyCredentials(QString email, QString password, QString pin)
|
|
|
|
{
|
|
|
|
setStartPageText(tr("Testing cloud credentials"));
|
|
|
|
if (pin.isEmpty())
|
2019-11-03 12:36:35 +00:00
|
|
|
appendTextToLog(QStringLiteral("verify credentials for email %1 (no PIN)").arg(email));
|
2019-09-10 10:19:36 +00:00
|
|
|
else
|
|
|
|
appendTextToLog(QStringLiteral("verify credentials for email %1 PIN %2").arg(email, pin));
|
|
|
|
CloudStorageAuthenticate *csa = new CloudStorageAuthenticate(this);
|
|
|
|
csa->backend(email, password, pin);
|
|
|
|
// let's wait here for the signal to avoid too many more nested functions
|
|
|
|
QTimer myTimer;
|
|
|
|
myTimer.setSingleShot(true);
|
|
|
|
QEventLoop loop;
|
|
|
|
connect(csa, &CloudStorageAuthenticate::finishedAuthenticate, &loop, &QEventLoop::quit);
|
|
|
|
connect(&myTimer, &QTimer::timeout, &loop, &QEventLoop::quit);
|
|
|
|
myTimer.start(5000);
|
|
|
|
loop.exec();
|
|
|
|
if (!myTimer.isActive()) {
|
|
|
|
// got no response from the server
|
|
|
|
setStartPageText(RED_FONT + tr("No response from cloud server to validate the credentials") + END_FONT);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
myTimer.stop();
|
|
|
|
if (prefs.cloud_verification_status == qPrefCloudStorage::CS_INCORRECT_USER_PASSWD) {
|
|
|
|
appendTextToLog(QStringLiteral("Incorrect email / password combination"));
|
|
|
|
setStartPageText(RED_FONT + tr("Incorrect email / password combination") + END_FONT);
|
|
|
|
return false;
|
|
|
|
} else if (prefs.cloud_verification_status == qPrefCloudStorage::CS_NEED_TO_VERIFY) {
|
|
|
|
if (pin.isEmpty()) {
|
|
|
|
appendTextToLog(QStringLiteral("Cloud credentials require PIN entry"));
|
|
|
|
setStartPageText(RED_FONT + tr("Cloud credentials require verification PIN") + END_FONT);
|
|
|
|
} else {
|
|
|
|
appendTextToLog(QStringLiteral("PIN provided but not accepted"));
|
|
|
|
setStartPageText(RED_FONT + tr("Incorrect PIN, please try again") + END_FONT);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} else if (prefs.cloud_verification_status == qPrefCloudStorage::CS_VERIFIED) {
|
|
|
|
appendTextToLog(QStringLiteral("PIN accepted"));
|
|
|
|
setStartPageText(RED_FONT + tr("PIN accepted, credentials verified") + END_FONT);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-01-24 20:23:55 +00:00
|
|
|
void QMLManager::tryRetrieveDataFromBackend()
|
2015-12-05 03:34:59 +00:00
|
|
|
{
|
|
|
|
// if the cloud credentials are present, we should try to get the GPS Webservice ID
|
|
|
|
// and (if we haven't done so) load the dive list
|
2018-01-07 10:12:48 +00:00
|
|
|
if (!empty_string(prefs.cloud_storage_email) &&
|
|
|
|
!empty_string(prefs.cloud_storage_password)) {
|
2016-01-02 08:04:59 +00:00
|
|
|
setStartPageText(tr("Testing cloud credentials"));
|
2015-12-05 03:34:59 +00:00
|
|
|
appendTextToLog("Have credentials, let's see if they are valid");
|
2016-04-08 19:28:05 +00:00
|
|
|
CloudStorageAuthenticate *csa = new CloudStorageAuthenticate(this);
|
2019-12-27 13:39:31 +00:00
|
|
|
csa->backend(prefs.cloud_storage_email, prefs.cloud_storage_password, "");
|
|
|
|
|
2016-06-13 22:21:51 +00:00
|
|
|
// let's wait here for the signal to avoid too many more nested functions
|
|
|
|
QTimer myTimer;
|
|
|
|
myTimer.setSingleShot(true);
|
|
|
|
QEventLoop loop;
|
|
|
|
connect(csa, &CloudStorageAuthenticate::finishedAuthenticate, &loop, &QEventLoop::quit);
|
|
|
|
connect(&myTimer, &QTimer::timeout, &loop, &QEventLoop::quit);
|
|
|
|
myTimer.start(5000);
|
|
|
|
loop.exec();
|
|
|
|
if (!myTimer.isActive()) {
|
|
|
|
// got no response from the server
|
|
|
|
setStartPageText(RED_FONT + tr("No response from cloud server to validate the credentials") + END_FONT);
|
|
|
|
revertToNoCloudIfNeeded();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
myTimer.stop();
|
2018-09-02 14:22:16 +00:00
|
|
|
if (prefs.cloud_verification_status == qPrefCloudStorage::CS_INCORRECT_USER_PASSWD) {
|
2017-07-24 07:42:44 +00:00
|
|
|
appendTextToLog(QStringLiteral("Incorrect cloud credentials"));
|
|
|
|
setStartPageText(RED_FONT + tr("Incorrect cloud credentials") + END_FONT);
|
|
|
|
revertToNoCloudIfNeeded();
|
|
|
|
return;
|
2018-09-02 14:22:16 +00:00
|
|
|
} else if (prefs.cloud_verification_status != qPrefCloudStorage::CS_VERIFIED) {
|
2016-06-13 22:21:51 +00:00
|
|
|
// here we need to enter the PIN
|
2017-07-29 07:37:35 +00:00
|
|
|
appendTextToLog(QStringLiteral("Need to verify the email address - enter PIN"));
|
2016-06-13 22:21:51 +00:00
|
|
|
setStartPageText(RED_FONT + tr("Cannot connect to cloud storage - cloud account not verified") + END_FONT);
|
|
|
|
revertToNoCloudIfNeeded();
|
|
|
|
return;
|
|
|
|
}
|
2016-06-13 23:42:36 +00:00
|
|
|
|
2016-06-13 22:21:51 +00:00
|
|
|
// now check the redirect URL to make sure everything is set up on the cloud server
|
2016-01-26 14:45:03 +00:00
|
|
|
connect(manager(), &QNetworkAccessManager::authenticationRequired, this, &QMLManager::provideAuth, Qt::UniqueConnection);
|
2015-12-05 03:34:59 +00:00
|
|
|
QUrl url(CLOUDREDIRECTURL);
|
2018-05-26 13:22:22 +00:00
|
|
|
QNetworkRequest request(url);
|
2015-12-05 03:34:59 +00:00
|
|
|
request.setRawHeader("User-Agent", getUserAgent().toUtf8());
|
|
|
|
request.setRawHeader("Accept", "text/html");
|
2018-05-26 13:22:22 +00:00
|
|
|
QNetworkReply *reply = manager()->get(request);
|
2015-12-05 03:34:59 +00:00
|
|
|
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(handleError(QNetworkReply::NetworkError)));
|
|
|
|
connect(reply, &QNetworkReply::sslErrors, this, &QMLManager::handleSslErrors);
|
2018-05-26 13:22:22 +00:00
|
|
|
connect(reply, &QNetworkReply::finished, this, &QMLManager::retrieveUserid);
|
2015-11-18 21:14:19 +00:00
|
|
|
}
|
2015-12-05 03:34:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::provideAuth(QNetworkReply *reply, QAuthenticator *auth)
|
|
|
|
{
|
|
|
|
if (auth->user() == QString(prefs.cloud_storage_email) &&
|
|
|
|
auth->password() == QString(prefs.cloud_storage_password)) {
|
|
|
|
// OK, credentials have been tried and didn't work, so they are invalid
|
|
|
|
appendTextToLog("Cloud credentials are invalid");
|
2016-03-11 05:59:16 +00:00
|
|
|
setStartPageText(RED_FONT + tr("Cloud credentials are invalid") + END_FONT);
|
2019-12-28 17:18:06 +00:00
|
|
|
qPrefCloudStorage::set_cloud_verification_status(qPrefCloudStorage::CS_INCORRECT_USER_PASSWD);
|
2015-12-05 03:34:59 +00:00
|
|
|
reply->disconnect();
|
|
|
|
reply->abort();
|
|
|
|
reply->deleteLater();
|
2015-11-30 18:15:04 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-12-05 03:34:59 +00:00
|
|
|
auth->setUser(prefs.cloud_storage_email);
|
|
|
|
auth->setPassword(prefs.cloud_storage_password);
|
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::handleSslErrors(const QList<QSslError> &errors)
|
|
|
|
{
|
2018-05-26 13:22:22 +00:00
|
|
|
auto *reply = qobject_cast<QNetworkReply *>(sender());
|
2016-03-11 05:59:16 +00:00
|
|
|
setStartPageText(RED_FONT + tr("Cannot open cloud storage: Error creating https connection") + END_FONT);
|
2019-04-01 20:15:19 +00:00
|
|
|
for (QSslError e: errors) {
|
2017-06-18 06:23:41 +00:00
|
|
|
appendTextToLog(e.errorString());
|
2015-12-05 03:34:59 +00:00
|
|
|
}
|
|
|
|
reply->abort();
|
|
|
|
reply->deleteLater();
|
2017-06-18 06:22:37 +00:00
|
|
|
setNotificationText(QStringLiteral(""));
|
2015-12-05 03:34:59 +00:00
|
|
|
}
|
2015-11-30 18:15:04 +00:00
|
|
|
|
2015-12-05 03:34:59 +00:00
|
|
|
void QMLManager::handleError(QNetworkReply::NetworkError nError)
|
|
|
|
{
|
2018-05-26 13:22:22 +00:00
|
|
|
auto *reply = qobject_cast<QNetworkReply *>(sender());
|
2015-12-15 07:00:19 +00:00
|
|
|
QString errorString = reply->errorString();
|
2017-06-18 06:23:41 +00:00
|
|
|
appendTextToLog(QStringLiteral("handleError ") + nError + QStringLiteral(": ") + errorString);
|
2016-03-11 05:59:16 +00:00
|
|
|
setStartPageText(RED_FONT + tr("Cannot open cloud storage: %1").arg(errorString) + END_FONT);
|
2015-12-05 03:34:59 +00:00
|
|
|
reply->abort();
|
|
|
|
reply->deleteLater();
|
2017-06-18 06:22:37 +00:00
|
|
|
setNotificationText(QStringLiteral(""));
|
2015-12-05 03:34:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::retrieveUserid()
|
|
|
|
{
|
2018-05-26 13:22:22 +00:00
|
|
|
auto *reply = qobject_cast<QNetworkReply *>(sender());
|
2015-12-05 03:34:59 +00:00
|
|
|
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) != 302) {
|
2016-04-30 17:15:15 +00:00
|
|
|
appendTextToLog(QStringLiteral("Cloud storage connection not working correctly: (%1) %2")
|
2020-01-27 00:51:01 +00:00
|
|
|
.arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt())
|
|
|
|
.arg(QString(reply->readAll())));
|
2016-04-06 04:27:05 +00:00
|
|
|
setStartPageText(RED_FONT + tr("Cannot connect to cloud storage") + END_FONT);
|
2016-04-29 13:28:09 +00:00
|
|
|
revertToNoCloudIfNeeded();
|
2015-12-05 03:34:59 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-12-28 17:18:06 +00:00
|
|
|
qPrefCloudStorage::set_cloud_verification_status(qPrefCloudStorage::CS_VERIFIED);
|
2017-06-18 06:50:22 +00:00
|
|
|
setStartPageText(tr("Cloud credentials valid, loading dives..."));
|
2016-04-06 18:47:12 +00:00
|
|
|
// this only gets called with "alreadySaving" already locked
|
2016-02-08 19:12:43 +00:00
|
|
|
loadDivesWithValidCredentials();
|
2015-12-05 03:34:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::loadDivesWithValidCredentials()
|
|
|
|
{
|
2015-07-10 08:31:24 +00:00
|
|
|
QString url;
|
2018-01-17 20:15:43 +00:00
|
|
|
timestamp_t currentDiveTimestamp = m_selectedDiveTimestamp;
|
2015-07-10 08:31:24 +00:00
|
|
|
if (getCloudURL(url)) {
|
2018-01-24 21:56:52 +00:00
|
|
|
setStartPageText(RED_FONT + tr("Cloud storage error: %1").arg(consumeError()) + END_FONT);
|
2016-04-29 13:28:09 +00:00
|
|
|
revertToNoCloudIfNeeded();
|
2015-07-10 08:31:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-01-11 14:14:45 +00:00
|
|
|
QByteArray fileNamePrt = QFile::encodeName(url);
|
2016-04-06 05:51:09 +00:00
|
|
|
git_repository *git;
|
|
|
|
const char *branch;
|
|
|
|
int error;
|
|
|
|
if (check_git_sha(fileNamePrt.data(), &git, &branch) == 0) {
|
2015-12-27 18:05:19 +00:00
|
|
|
appendTextToLog("Cloud sync shows local cache was current");
|
2016-04-29 13:28:09 +00:00
|
|
|
goto successful_exit;
|
2015-12-27 18:05:19 +00:00
|
|
|
}
|
2016-04-06 04:27:05 +00:00
|
|
|
appendTextToLog("Cloud sync brought newer data, reloading the dive list");
|
2016-04-14 13:01:36 +00:00
|
|
|
|
2018-06-18 09:14:05 +00:00
|
|
|
// if we aren't switching from no-cloud mode, let's clear the dive data
|
|
|
|
if (!noCloudToCloud) {
|
|
|
|
appendTextToLog("Clear out in memory dive data");
|
2019-09-26 11:37:44 +00:00
|
|
|
DiveListModel::instance()->clear();
|
2018-06-18 09:14:05 +00:00
|
|
|
} else {
|
|
|
|
appendTextToLog("Switching from no cloud mode; keep in memory dive data");
|
|
|
|
}
|
2016-04-06 05:51:09 +00:00
|
|
|
if (git != dummy_git_repository) {
|
|
|
|
appendTextToLog(QString("have repository and branch %1").arg(branch));
|
|
|
|
error = git_load_dives(git, branch);
|
|
|
|
} else {
|
|
|
|
appendTextToLog(QString("didn't receive valid git repo, try again"));
|
2019-02-28 21:45:17 +00:00
|
|
|
error = parse_file(fileNamePrt.data(), &dive_table, &trip_table, &dive_site_table);
|
2016-04-06 05:51:09 +00:00
|
|
|
}
|
2015-07-10 08:31:24 +00:00
|
|
|
if (!error) {
|
2015-07-13 00:39:13 +00:00
|
|
|
report_error("filename is now %s", fileNamePrt.data());
|
2017-12-10 21:22:13 +00:00
|
|
|
set_filename(fileNamePrt.data());
|
2015-07-13 00:39:13 +00:00
|
|
|
} else {
|
2015-12-01 17:37:47 +00:00
|
|
|
report_error("failed to open file %s", fileNamePrt.data());
|
2018-01-24 21:56:52 +00:00
|
|
|
setNotificationText(consumeError());
|
2016-04-29 13:28:09 +00:00
|
|
|
revertToNoCloudIfNeeded();
|
2017-12-11 22:20:18 +00:00
|
|
|
set_filename(NULL);
|
2015-12-03 01:50:47 +00:00
|
|
|
return;
|
2015-07-10 08:31:24 +00:00
|
|
|
}
|
2016-04-22 14:10:20 +00:00
|
|
|
consumeFinishedLoad(currentDiveTimestamp);
|
2016-04-29 13:28:09 +00:00
|
|
|
|
|
|
|
successful_exit:
|
|
|
|
alreadySaving = false;
|
2016-04-22 14:10:20 +00:00
|
|
|
setLoadFromCloud(true);
|
2016-04-29 13:28:09 +00:00
|
|
|
// if we came from local storage mode, let's merge the local data into the local cache
|
|
|
|
// for the remote data - which then later gets merged with the remote data if necessary
|
2018-06-18 09:14:05 +00:00
|
|
|
if (noCloudToCloud) {
|
2017-06-18 06:50:22 +00:00
|
|
|
git_storage_update_progress(qPrintable(tr("Loading dives from local storage ('no cloud' mode)")));
|
2016-04-29 13:28:09 +00:00
|
|
|
mergeLocalRepo();
|
2019-08-14 16:09:17 +00:00
|
|
|
DiveListModel::instance()->reload();
|
2016-04-29 13:28:09 +00:00
|
|
|
appendTextToLog(QStringLiteral("%1 dives loaded after importing nocloud local storage").arg(dive_table.nr));
|
2018-06-18 09:14:05 +00:00
|
|
|
noCloudToCloud = false;
|
2018-10-08 17:10:11 +00:00
|
|
|
mark_divelist_changed(true);
|
2016-04-29 13:28:09 +00:00
|
|
|
saveChangesLocal();
|
2018-10-09 08:23:24 +00:00
|
|
|
if (git_local_only == false) {
|
2016-04-29 13:28:09 +00:00
|
|
|
appendTextToLog(QStringLiteral("taking things back offline now that storage is synced"));
|
2018-10-09 08:23:24 +00:00
|
|
|
git_local_only = true;
|
2016-04-29 13:28:09 +00:00
|
|
|
}
|
|
|
|
}
|
2016-04-30 18:08:33 +00:00
|
|
|
// if we got here just for an initial connection to the cloud, reset to offline
|
|
|
|
if (currentGitLocalOnly) {
|
|
|
|
currentGitLocalOnly = false;
|
2018-09-10 13:30:01 +00:00
|
|
|
git_local_only = true;
|
2016-04-30 18:08:33 +00:00
|
|
|
}
|
2016-04-29 13:28:09 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::revertToNoCloudIfNeeded()
|
|
|
|
{
|
2016-04-30 18:08:33 +00:00
|
|
|
if (currentGitLocalOnly) {
|
|
|
|
// we tried to connect to the cloud for the first time and that failed
|
|
|
|
currentGitLocalOnly = false;
|
2018-09-10 13:30:01 +00:00
|
|
|
git_local_only = true;
|
2016-04-30 18:08:33 +00:00
|
|
|
}
|
2019-12-29 11:33:30 +00:00
|
|
|
if (m_oldStatus == qPrefCloudStorage::CS_NOCLOUD) {
|
2016-04-29 13:28:09 +00:00
|
|
|
// we tried to switch to a cloud account and had previously used local data,
|
|
|
|
// but connecting to the cloud account (and subsequently merging the local
|
|
|
|
// and cloud data) failed - so let's delete the cloud credentials and go
|
2017-08-03 12:55:09 +00:00
|
|
|
// back to CS_NOCLOUD mode in order to prevent us from losing the locally stored
|
2016-04-29 13:28:09 +00:00
|
|
|
// dives
|
2018-10-09 08:23:24 +00:00
|
|
|
if (git_local_only == true) {
|
2016-04-29 13:28:09 +00:00
|
|
|
appendTextToLog(QStringLiteral("taking things back offline since sync with cloud failed"));
|
2018-10-09 08:23:24 +00:00
|
|
|
git_local_only = false;
|
2016-04-29 13:28:09 +00:00
|
|
|
}
|
2017-11-18 18:57:50 +00:00
|
|
|
free((void *)prefs.cloud_storage_email);
|
2016-04-29 13:28:09 +00:00
|
|
|
prefs.cloud_storage_email = NULL;
|
2017-11-18 18:57:50 +00:00
|
|
|
free((void *)prefs.cloud_storage_password);
|
2016-04-29 13:28:09 +00:00
|
|
|
prefs.cloud_storage_password = NULL;
|
2019-12-20 15:35:12 +00:00
|
|
|
qPrefCloudStorage::set_cloud_storage_email("");
|
2019-12-20 16:04:28 +00:00
|
|
|
qPrefCloudStorage::set_cloud_storage_password("");
|
2019-12-29 11:33:30 +00:00
|
|
|
setOldStatus((qPrefCloudStorage::cloud_status)qPrefCloudStorage::cloud_verification_status());
|
2019-12-28 17:29:47 +00:00
|
|
|
qPrefCloudStorage::set_cloud_verification_status(qPrefCloudStorage::CS_NOCLOUD);
|
2017-12-10 21:22:13 +00:00
|
|
|
set_filename(NOCLOUD_LOCALSTORAGE);
|
2016-04-29 13:28:09 +00:00
|
|
|
setStartPageText(RED_FONT + tr("Failed to connect to cloud server, reverting to no cloud status") + END_FONT);
|
|
|
|
}
|
|
|
|
alreadySaving = false;
|
2016-04-22 14:10:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::consumeFinishedLoad(timestamp_t currentDiveTimestamp)
|
|
|
|
{
|
2017-02-04 16:55:25 +00:00
|
|
|
prefs.unit_system = git_prefs.unit_system;
|
|
|
|
if (git_prefs.unit_system == IMPERIAL)
|
|
|
|
git_prefs.units = IMPERIAL_units;
|
2017-03-11 23:44:55 +00:00
|
|
|
else if (git_prefs.unit_system == METRIC)
|
|
|
|
git_prefs.units = SI_units;
|
2017-02-04 16:55:25 +00:00
|
|
|
prefs.units = git_prefs.units;
|
2017-02-04 09:42:00 +00:00
|
|
|
prefs.tankbar = git_prefs.tankbar;
|
|
|
|
prefs.dcceiling = git_prefs.dcceiling;
|
2017-03-25 12:03:37 +00:00
|
|
|
prefs.show_ccr_setpoint = git_prefs.show_ccr_setpoint;
|
|
|
|
prefs.show_ccr_sensors = git_prefs.show_ccr_sensors;
|
|
|
|
prefs.pp_graphs.po2 = git_prefs.pp_graphs.po2;
|
2018-09-23 10:53:35 +00:00
|
|
|
process_loaded_dives();
|
2019-08-14 16:09:17 +00:00
|
|
|
DiveListModel::instance()->reload();
|
2016-04-14 18:48:04 +00:00
|
|
|
if (currentDiveTimestamp)
|
2019-09-28 21:31:40 +00:00
|
|
|
setUpdateSelectedDive(DiveListSortModel::instance()->getIdxForId(get_dive_id_closest_to(currentDiveTimestamp)));
|
2016-04-06 04:17:37 +00:00
|
|
|
appendTextToLog(QStringLiteral("%1 dives loaded").arg(dive_table.nr));
|
2015-12-15 07:00:19 +00:00
|
|
|
if (dive_table.nr == 0)
|
|
|
|
setStartPageText(tr("Cloud storage open successfully. No dives in dive list."));
|
2016-04-06 18:47:12 +00:00
|
|
|
alreadySaving = false;
|
2015-07-17 15:28:01 +00:00
|
|
|
}
|
|
|
|
|
2016-01-11 03:34:21 +00:00
|
|
|
void QMLManager::refreshDiveList()
|
|
|
|
{
|
2019-08-14 16:09:17 +00:00
|
|
|
DiveListModel::instance()->reload();
|
2016-01-11 03:34:21 +00:00
|
|
|
}
|
|
|
|
|
2019-08-10 15:41:35 +00:00
|
|
|
void QMLManager::setupDivesite(struct dive *d, struct dive_site *ds, double lat, double lon, const char *locationtext)
|
2015-07-17 15:28:01 +00:00
|
|
|
{
|
2018-10-20 18:12:15 +00:00
|
|
|
location_t location = create_location(lat, lon);
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
if (ds) {
|
2018-10-20 18:12:15 +00:00
|
|
|
ds->location = location;
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
} else {
|
2019-03-05 21:58:47 +00:00
|
|
|
unregister_dive_from_dive_site(d);
|
|
|
|
add_dive_to_dive_site(d, create_dive_site_with_gps(locationtext, &location, &dive_site_table));
|
2019-08-10 15:41:35 +00:00
|
|
|
// We created a new dive site - let the dive site model know.
|
|
|
|
updateSiteList();
|
2015-12-27 05:24:29 +00:00
|
|
|
}
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
}
|
2015-07-17 15:28:01 +00:00
|
|
|
|
2019-08-13 07:35:18 +00:00
|
|
|
bool QMLManager::checkDate(const DiveObjectHelper &myDive, struct dive * d, QString date)
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
{
|
2019-08-13 07:35:18 +00:00
|
|
|
QString oldDate = myDive.date() + " " + myDive.time();
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
if (date != oldDate) {
|
2016-01-06 06:53:32 +00:00
|
|
|
QDateTime newDate;
|
|
|
|
// what a pain - Qt will not parse dates if the day of the week is incorrect
|
|
|
|
// so if the user changed the date but didn't update the day of the week (most likely behavior, actually),
|
|
|
|
// we need to make sure we don't try to parse that
|
2017-12-17 08:02:48 +00:00
|
|
|
QString format(QString(prefs.date_format_short) + QChar(' ') + prefs.time_format);
|
2016-01-26 15:02:42 +00:00
|
|
|
if (format.contains(QLatin1String("ddd")) || format.contains(QLatin1String("dddd"))) {
|
|
|
|
QString dateFormatToDrop = format.contains(QLatin1String("ddd")) ? QStringLiteral("ddd") : QStringLiteral("dddd");
|
2016-01-06 06:53:32 +00:00
|
|
|
QDateTime ts;
|
|
|
|
QLocale loc = getLocale();
|
|
|
|
ts.setMSecsSinceEpoch(d->when * 1000L);
|
|
|
|
QString drop = loc.toString(ts.toUTC(), dateFormatToDrop);
|
|
|
|
format.replace(dateFormatToDrop, "");
|
|
|
|
date.replace(drop, "");
|
|
|
|
}
|
2017-04-16 01:51:03 +00:00
|
|
|
// set date from string and make sure it's treated as UTC (like all our time stamps)
|
2016-01-06 06:53:32 +00:00
|
|
|
newDate = QDateTime::fromString(date, format);
|
2017-04-16 01:51:03 +00:00
|
|
|
newDate.setTimeSpec(Qt::UTC);
|
2016-03-11 02:36:46 +00:00
|
|
|
if (!newDate.isValid()) {
|
2017-06-18 06:23:41 +00:00
|
|
|
appendTextToLog("unable to parse date " + date + " with the given format " + format);
|
2016-03-11 02:36:46 +00:00
|
|
|
QRegularExpression isoDate("\\d+-\\d+-\\d+[^\\d]+\\d+:\\d+");
|
|
|
|
if (date.contains(isoDate)) {
|
|
|
|
newDate = QDateTime::fromString(date, "yyyy-M-d h:m:s");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
newDate = QDateTime::fromString(date, "yy-M-d h:m:s");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
}
|
|
|
|
QRegularExpression isoDateNoSecs("\\d+-\\d+-\\d+[^\\d]+\\d+");
|
|
|
|
if (date.contains(isoDateNoSecs)) {
|
|
|
|
newDate = QDateTime::fromString(date, "yyyy-M-d h:m");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
newDate = QDateTime::fromString(date, "yy-M-d h:m");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
}
|
|
|
|
QRegularExpression usDate("\\d+/\\d+/\\d+[^\\d]+\\d+:\\d+:\\d+");
|
|
|
|
if (date.contains(usDate)) {
|
|
|
|
newDate = QDateTime::fromString(date, "M/d/yyyy h:m:s");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
newDate = QDateTime::fromString(date, "M/d/yy h:m:s");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
newDate = QDateTime::fromString(date.toLower(), "M/d/yyyy h:m:sap");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
newDate = QDateTime::fromString(date.toLower(), "M/d/yy h:m:sap");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
}
|
|
|
|
QRegularExpression usDateNoSecs("\\d+/\\d+/\\d+[^\\d]+\\d+:\\d+");
|
|
|
|
if (date.contains(usDateNoSecs)) {
|
|
|
|
newDate = QDateTime::fromString(date, "M/d/yyyy h:m");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
newDate = QDateTime::fromString(date, "M/d/yy h:m");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
newDate = QDateTime::fromString(date.toLower(), "M/d/yyyy h:map");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
newDate = QDateTime::fromString(date.toLower(), "M/d/yy h:map");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
}
|
|
|
|
QRegularExpression leDate("\\d+\\.\\d+\\.\\d+[^\\d]+\\d+:\\d+:\\d+");
|
|
|
|
if (date.contains(leDate)) {
|
|
|
|
newDate = QDateTime::fromString(date, "d.M.yyyy h:m:s");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
newDate = QDateTime::fromString(date, "d.M.yy h:m:s");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
}
|
|
|
|
QRegularExpression leDateNoSecs("\\d+\\.\\d+\\.\\d+[^\\d]+\\d+:\\d+");
|
|
|
|
if (date.contains(leDateNoSecs)) {
|
|
|
|
newDate = QDateTime::fromString(date, "d.M.yyyy h:m");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
newDate = QDateTime::fromString(date, "d.M.yy h:m");
|
|
|
|
if (newDate.isValid())
|
|
|
|
goto parsed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
parsed:
|
2016-01-27 20:07:10 +00:00
|
|
|
if (newDate.isValid()) {
|
|
|
|
// stupid Qt... two digit years are always 19xx - WTF???
|
|
|
|
// so if adding a hundred years gets you into something before a year from now...
|
|
|
|
// add a hundred years.
|
|
|
|
if (newDate.addYears(100) < QDateTime::currentDateTime().addYears(1))
|
|
|
|
newDate = newDate.addYears(100);
|
2016-06-22 20:46:22 +00:00
|
|
|
d->dc.when = d->when = newDate.toMSecsSinceEpoch() / 1000;
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
return true;
|
2016-01-27 20:07:10 +00:00
|
|
|
}
|
2017-06-18 06:23:41 +00:00
|
|
|
appendTextToLog("none of our parsing attempts worked for the date string");
|
2016-01-06 06:53:32 +00:00
|
|
|
}
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
return false;
|
|
|
|
}
|
2016-04-14 19:39:32 +00:00
|
|
|
|
2019-08-13 07:35:18 +00:00
|
|
|
bool QMLManager::checkLocation(const DiveObjectHelper &myDive, struct dive *d, QString location, QString gps)
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
{
|
|
|
|
bool diveChanged = false;
|
2017-12-12 13:48:41 +00:00
|
|
|
struct dive_site *ds = get_dive_site_for_dive(d);
|
2019-08-13 20:48:18 +00:00
|
|
|
qDebug() << "checkLocation" << location << "gps" << gps << "dive had" << myDive.location << "gps" << myDive.gas;
|
|
|
|
if (myDive.location != location) {
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
diveChanged = true;
|
2019-02-26 21:26:11 +00:00
|
|
|
ds = get_dive_site_by_name(qPrintable(location), &dive_site_table);
|
2018-12-28 09:22:10 +00:00
|
|
|
if (!ds && !location.isEmpty())
|
2019-03-03 17:39:12 +00:00
|
|
|
ds = create_dive_site(qPrintable(location), &dive_site_table);
|
2019-03-05 21:58:47 +00:00
|
|
|
unregister_dive_from_dive_site(d);
|
|
|
|
add_dive_to_dive_site(d, ds);
|
2019-08-10 15:41:35 +00:00
|
|
|
// We created a new dive site - let the dive site model know.
|
|
|
|
updateSiteList();
|
2015-12-27 06:57:47 +00:00
|
|
|
}
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
// now make sure that the GPS coordinates match - if the user changed the name but not
|
|
|
|
// the GPS coordinates, this still does the right thing as the now new dive site will
|
|
|
|
// have no coordinates, so the coordinates from the edit screen will get added
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.gps != gps) {
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
double lat, lon;
|
|
|
|
if (parseGpsText(gps, &lat, &lon)) {
|
2018-04-14 20:26:30 +00:00
|
|
|
qDebug() << "parsed GPS, using it";
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
// there are valid GPS coordinates - just use them
|
2019-08-13 20:48:18 +00:00
|
|
|
setupDivesite(d, ds, lat, lon, qPrintable(myDive.location));
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
diveChanged = true;
|
|
|
|
} else if (gps == GPS_CURRENT_POS) {
|
2018-04-14 20:26:30 +00:00
|
|
|
qDebug() << "gps was our default text for no GPS";
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
// user asked to use current pos
|
|
|
|
QString gpsString = getCurrentPosition();
|
|
|
|
if (gpsString != GPS_CURRENT_POS) {
|
2018-04-14 20:26:30 +00:00
|
|
|
qDebug() << "but now I got a valid location" << gpsString;
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
if (parseGpsText(qPrintable(gpsString), &lat, &lon)) {
|
2019-08-13 20:48:18 +00:00
|
|
|
setupDivesite(d, ds, lat, lon, qPrintable(myDive.location));
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
diveChanged = true;
|
2016-01-27 14:29:14 +00:00
|
|
|
}
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
} else {
|
|
|
|
appendTextToLog("couldn't get GPS location in time");
|
2016-01-02 01:23:29 +00:00
|
|
|
}
|
2016-01-27 14:29:14 +00:00
|
|
|
} else {
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
// just something we can't parse, so tell the user
|
|
|
|
appendTextToLog(QString("wasn't able to parse gps string '%1'").arg(gps));
|
2016-01-02 01:23:29 +00:00
|
|
|
}
|
|
|
|
}
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
return diveChanged;
|
|
|
|
}
|
|
|
|
|
2019-08-13 07:35:18 +00:00
|
|
|
bool QMLManager::checkDuration(const DiveObjectHelper &myDive, struct dive *d, QString duration)
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
{
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.duration != duration) {
|
2016-01-01 08:23:15 +00:00
|
|
|
int h = 0, m = 0, s = 0;
|
2016-02-06 20:07:42 +00:00
|
|
|
QRegExp r1(QStringLiteral("(\\d*)\\s*%1[\\s,:]*(\\d*)\\s*%2[\\s,:]*(\\d*)\\s*%3").arg(tr("h")).arg(tr("min")).arg(tr("sec")), Qt::CaseInsensitive);
|
|
|
|
QRegExp r2(QStringLiteral("(\\d*)\\s*%1[\\s,:]*(\\d*)\\s*%2").arg(tr("h")).arg(tr("min")), Qt::CaseInsensitive);
|
|
|
|
QRegExp r3(QStringLiteral("(\\d*)\\s*%1").arg(tr("min")), Qt::CaseInsensitive);
|
2016-01-26 15:02:42 +00:00
|
|
|
QRegExp r4(QStringLiteral("(\\d*):(\\d*):(\\d*)"));
|
|
|
|
QRegExp r5(QStringLiteral("(\\d*):(\\d*)"));
|
2016-02-09 21:00:56 +00:00
|
|
|
QRegExp r6(QStringLiteral("(\\d*)"));
|
2016-01-01 08:23:15 +00:00
|
|
|
if (r1.indexIn(duration) >= 0) {
|
|
|
|
h = r1.cap(1).toInt();
|
|
|
|
m = r1.cap(2).toInt();
|
|
|
|
s = r1.cap(3).toInt();
|
|
|
|
} else if (r2.indexIn(duration) >= 0) {
|
|
|
|
h = r2.cap(1).toInt();
|
|
|
|
m = r2.cap(2).toInt();
|
|
|
|
} else if (r3.indexIn(duration) >= 0) {
|
|
|
|
m = r3.cap(1).toInt();
|
|
|
|
} else if (r4.indexIn(duration) >= 0) {
|
|
|
|
h = r4.cap(1).toInt();
|
|
|
|
m = r4.cap(2).toInt();
|
|
|
|
s = r4.cap(3).toInt();
|
|
|
|
} else if (r5.indexIn(duration) >= 0) {
|
|
|
|
h = r5.cap(1).toInt();
|
|
|
|
m = r5.cap(2).toInt();
|
2016-02-09 21:00:56 +00:00
|
|
|
} else if (r6.indexIn(duration) >= 0) {
|
|
|
|
m = r6.cap(1).toInt();
|
2016-01-01 08:23:15 +00:00
|
|
|
}
|
2016-01-11 06:08:42 +00:00
|
|
|
d->dc.duration.seconds = d->duration.seconds = h * 3600 + m * 60 + s;
|
2018-06-20 00:20:32 +00:00
|
|
|
if (same_string(d->dc.model, "manually added dive"))
|
|
|
|
free_samples(&d->dc);
|
|
|
|
else
|
2017-06-18 06:23:41 +00:00
|
|
|
appendTextToLog("Cannot change the duration on a dive that wasn't manually added");
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
return true;
|
2016-01-01 08:23:15 +00:00
|
|
|
}
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-08-13 07:35:18 +00:00
|
|
|
bool QMLManager::checkDepth(const DiveObjectHelper &myDive, dive *d, QString depth)
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
{
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.depth != depth) {
|
2016-02-21 06:11:03 +00:00
|
|
|
int depthValue = parseLengthToMm(depth);
|
|
|
|
// the QML code should stop negative depth, but massively huge depth can make
|
|
|
|
// the profile extremely slow or even run out of memory and crash, so keep
|
|
|
|
// the depth <= 500m
|
|
|
|
if (0 <= depthValue && depthValue <= 500000) {
|
|
|
|
d->maxdepth.mm = depthValue;
|
|
|
|
if (same_string(d->dc.model, "manually added dive")) {
|
|
|
|
d->dc.maxdepth.mm = d->maxdepth.mm;
|
2018-06-20 00:20:32 +00:00
|
|
|
free_samples(&d->dc);
|
2016-02-21 06:11:03 +00:00
|
|
|
}
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
return true;
|
2016-02-15 15:51:23 +00:00
|
|
|
}
|
2016-01-01 08:32:30 +00:00
|
|
|
}
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// update the dive and return the notes field, stripped of the HTML junk
|
2019-10-21 00:13:59 +00:00
|
|
|
void QMLManager::commitChanges(QString diveId, QString number, QString date, QString location, QString gps, QString duration, QString depth,
|
2020-01-27 00:51:01 +00:00
|
|
|
QString airtemp, QString watertemp, QString suit, QString buddy, QString diveMaster, QString weight, QString notes,
|
|
|
|
QStringList startpressure, QStringList endpressure, QStringList gasmix, QStringList usedCylinder, int rating, int visibility, QString state)
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
{
|
|
|
|
struct dive *d = get_dive_by_uniq_id(diveId.toInt());
|
2017-12-26 21:37:40 +00:00
|
|
|
|
|
|
|
if (!d) {
|
|
|
|
appendTextToLog("cannot commit changes: no dive");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-13 07:35:18 +00:00
|
|
|
DiveObjectHelper myDive(d);
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
|
|
|
|
// notes comes back as rich text - let's convert this into plain text
|
|
|
|
QTextDocument doc;
|
|
|
|
doc.setHtml(notes);
|
|
|
|
notes = doc.toPlainText();
|
|
|
|
|
|
|
|
bool diveChanged = false;
|
|
|
|
bool needResort = false;
|
|
|
|
|
|
|
|
diveChanged = needResort = checkDate(myDive, d, date);
|
|
|
|
|
|
|
|
diveChanged |= checkLocation(myDive, d, location, gps);
|
|
|
|
|
|
|
|
diveChanged |= checkDuration(myDive, d, duration);
|
|
|
|
|
|
|
|
diveChanged |= checkDepth(myDive, d, depth);
|
|
|
|
|
2019-10-21 00:13:59 +00:00
|
|
|
if (QString::number(myDive.number) != number) {
|
|
|
|
diveChanged = true;
|
|
|
|
d->number = number.toInt();
|
|
|
|
}
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.airTemp != airtemp) {
|
2016-01-01 01:34:20 +00:00
|
|
|
diveChanged = true;
|
|
|
|
d->airtemp.mkelvin = parseTemperatureToMkelvin(airtemp);
|
|
|
|
}
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.waterTemp != watertemp) {
|
2016-01-01 01:34:20 +00:00
|
|
|
diveChanged = true;
|
|
|
|
d->watertemp.mkelvin = parseTemperatureToMkelvin(watertemp);
|
|
|
|
}
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.sumWeight != weight) {
|
2019-08-10 16:10:02 +00:00
|
|
|
diveChanged = true;
|
|
|
|
// not sure what we'd do if there was more than one weight system
|
|
|
|
// defined - for now just ignore that case
|
|
|
|
if (d->weightsystems.nr == 0) {
|
2019-08-11 16:11:06 +00:00
|
|
|
weightsystem_t ws = { { parseWeightToGrams(weight) } , strdup(qPrintable(tr("weight"))) };
|
|
|
|
add_to_weightsystem_table(&d->weightsystems, 0, ws); // takes ownership of the string
|
2019-08-10 16:10:02 +00:00
|
|
|
} else if (d->weightsystems.nr == 1) {
|
2019-06-26 15:21:03 +00:00
|
|
|
d->weightsystems.weightsystems[0].weight.grams = parseWeightToGrams(weight);
|
2016-02-06 06:54:47 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-08 00:26:40 +00:00
|
|
|
// start and end pressures
|
|
|
|
// first, normalize the lists - QML gives us a list with just one empty string if nothing was entered
|
|
|
|
if (startpressure == QStringList(QString()))
|
|
|
|
startpressure = QStringList();
|
|
|
|
if (endpressure == QStringList(QString()))
|
|
|
|
endpressure = QStringList();
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.startPressure != startpressure || myDive.endPressure != endpressure) {
|
2016-02-09 16:20:17 +00:00
|
|
|
diveChanged = true;
|
2018-08-06 07:34:39 +00:00
|
|
|
for ( int i = 0, j = 0 ; j < startpressure.length() && j < endpressure.length() ; i++ ) {
|
2018-07-29 13:42:56 +00:00
|
|
|
if (state != "add" && !is_cylinder_used(d, i))
|
2018-08-06 07:34:39 +00:00
|
|
|
continue;
|
|
|
|
|
2020-02-08 00:26:40 +00:00
|
|
|
get_or_create_cylinder(d, i)->start.mbar = parsePressureToMbar(startpressure[j]);
|
2019-08-04 20:13:49 +00:00
|
|
|
get_cylinder(d, i)->end.mbar = parsePressureToMbar(endpressure[j]);
|
|
|
|
if (get_cylinder(d, i)->end.mbar > get_cylinder(d, i)->start.mbar)
|
|
|
|
get_cylinder(d, i)->end.mbar = get_cylinder(d, i)->start.mbar;
|
2018-08-06 07:34:39 +00:00
|
|
|
|
|
|
|
j++;
|
|
|
|
}
|
2016-02-09 16:20:17 +00:00
|
|
|
}
|
2016-02-13 17:34:31 +00:00
|
|
|
// gasmix for first cylinder
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.firstGas != gasmix) {
|
2018-08-06 07:29:00 +00:00
|
|
|
for ( int i = 0, j = 0 ; j < gasmix.length() ; i++ ) {
|
2018-07-29 13:42:56 +00:00
|
|
|
if (state != "add" && !is_cylinder_used(d, i))
|
2018-08-06 07:29:00 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
int o2 = parseGasMixO2(gasmix[j]);
|
|
|
|
int he = parseGasMixHE(gasmix[j]);
|
|
|
|
// the QML code SHOULD only accept valid gas mixes, but just to make sure
|
|
|
|
if (o2 >= 0 && o2 <= 1000 &&
|
2020-01-27 00:51:01 +00:00
|
|
|
he >= 0 && he <= 1000 &&
|
|
|
|
o2 + he <= 1000) {
|
2018-08-06 07:29:00 +00:00
|
|
|
diveChanged = true;
|
2020-02-08 00:26:40 +00:00
|
|
|
get_or_create_cylinder(d, i)->gasmix.o2.permille = o2;
|
2019-08-04 20:13:49 +00:00
|
|
|
get_cylinder(d, i)->gasmix.he.permille = he;
|
2018-08-06 07:29:00 +00:00
|
|
|
}
|
|
|
|
j++;
|
2016-02-21 06:11:03 +00:00
|
|
|
}
|
2016-02-13 17:34:31 +00:00
|
|
|
}
|
2016-08-30 14:24:19 +00:00
|
|
|
// info for first cylinder
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.getCylinder != usedCylinder) {
|
2016-08-30 14:24:19 +00:00
|
|
|
diveChanged = true;
|
2016-09-04 17:27:56 +00:00
|
|
|
unsigned long i;
|
2018-07-16 16:01:56 +00:00
|
|
|
int size = 0, wp = 0, j = 0, k = 0;
|
2019-08-04 16:44:57 +00:00
|
|
|
for (j = 0; k < usedCylinder.length(); j++) {
|
2018-07-29 13:42:56 +00:00
|
|
|
if (state != "add" && !is_cylinder_used(d, j))
|
2018-07-16 16:01:56 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_TANK_INFO && tank_info[i].name != NULL; i++) {
|
|
|
|
if (tank_info[i].name == usedCylinder[k] ) {
|
|
|
|
if (tank_info[i].ml > 0){
|
|
|
|
size = tank_info[i].ml;
|
|
|
|
wp = tank_info[i].bar * 1000;
|
|
|
|
} else {
|
|
|
|
size = (int) (cuft_to_l(tank_info[i].cuft) * 1000 / bar_to_atm(psi_to_bar(tank_info[i].psi)));
|
|
|
|
wp = psi_to_mbar(tank_info[i].psi);
|
|
|
|
}
|
|
|
|
break;
|
2016-08-30 14:24:19 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-08 00:26:40 +00:00
|
|
|
get_or_create_cylinder(d, j)->type.description = copy_qstring(usedCylinder[k]);
|
2019-08-04 20:13:49 +00:00
|
|
|
get_cylinder(d, j)->type.size.mliter = size;
|
|
|
|
get_cylinder(d, j)->type.workingpressure.mbar = wp;
|
2018-07-16 16:01:56 +00:00
|
|
|
k++;
|
2016-08-30 14:24:19 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.suit != suit) {
|
2015-07-17 15:28:01 +00:00
|
|
|
diveChanged = true;
|
|
|
|
free(d->suit);
|
2018-02-28 22:37:09 +00:00
|
|
|
d->suit = copy_qstring(suit);
|
2015-07-17 15:28:01 +00:00
|
|
|
}
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.buddy != buddy) {
|
2017-01-29 16:32:13 +00:00
|
|
|
if (buddy.contains(",")){
|
|
|
|
buddy = buddy.replace(QRegExp("\\s*,\\s*"), ", ");
|
|
|
|
}
|
2017-12-06 17:54:46 +00:00
|
|
|
diveChanged = true;
|
|
|
|
free(d->buddy);
|
2018-02-28 22:37:09 +00:00
|
|
|
d->buddy = copy_qstring(buddy);
|
2015-07-17 15:28:01 +00:00
|
|
|
}
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.divemaster != diveMaster) {
|
2018-11-13 20:28:18 +00:00
|
|
|
if (diveMaster.contains(",")){
|
|
|
|
diveMaster = diveMaster.replace(QRegExp("\\s*,\\s*"), ", ");
|
|
|
|
}
|
2015-07-17 15:28:01 +00:00
|
|
|
diveChanged = true;
|
|
|
|
free(d->divemaster);
|
2018-02-28 22:37:09 +00:00
|
|
|
d->divemaster = copy_qstring(diveMaster);
|
2015-07-17 15:28:01 +00:00
|
|
|
}
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.rating != rating) {
|
2017-07-28 17:28:52 +00:00
|
|
|
diveChanged = true;
|
|
|
|
d->rating = rating;
|
|
|
|
}
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.visibility != visibility) {
|
2017-07-28 17:28:52 +00:00
|
|
|
diveChanged = true;
|
|
|
|
d->visibility = visibility;
|
|
|
|
}
|
2019-08-13 20:48:18 +00:00
|
|
|
if (myDive.notes != notes) {
|
2015-07-17 15:28:01 +00:00
|
|
|
diveChanged = true;
|
|
|
|
free(d->notes);
|
2018-02-28 22:37:09 +00:00
|
|
|
d->notes = copy_qstring(notes);
|
2015-07-17 15:28:01 +00:00
|
|
|
}
|
2016-03-02 12:52:44 +00:00
|
|
|
// now that we have it all figured out, let's see what we need
|
|
|
|
// to update
|
|
|
|
DiveListModel *dm = DiveListModel::instance();
|
2017-04-16 02:06:46 +00:00
|
|
|
int modelIdx = dm->getDiveIdx(d->id);
|
2016-01-27 20:11:37 +00:00
|
|
|
int oldIdx = get_idx_by_uniq_id(d->id);
|
|
|
|
if (needResort) {
|
|
|
|
// we know that the only thing that might happen in a resort is that
|
|
|
|
// this one dive moves to a different spot in the dive list
|
2018-11-24 09:11:07 +00:00
|
|
|
sort_dive_table(&dive_table);
|
2018-11-24 11:31:35 +00:00
|
|
|
sort_trip_table(&trip_table);
|
2016-01-27 20:11:37 +00:00
|
|
|
int newIdx = get_idx_by_uniq_id(d->id);
|
|
|
|
if (newIdx != oldIdx) {
|
2017-04-16 02:06:46 +00:00
|
|
|
DiveListModel::instance()->removeDive(modelIdx);
|
|
|
|
modelIdx += (newIdx - oldIdx);
|
2019-08-13 15:22:15 +00:00
|
|
|
DiveListModel::instance()->insertDive(modelIdx);
|
2017-04-16 02:06:46 +00:00
|
|
|
diveChanged = true; // because we already modified things
|
2016-01-27 20:11:37 +00:00
|
|
|
}
|
|
|
|
}
|
2016-02-20 15:33:05 +00:00
|
|
|
if (diveChanged) {
|
|
|
|
if (d->maxdepth.mm == d->dc.maxdepth.mm &&
|
|
|
|
d->maxdepth.mm > 0 &&
|
|
|
|
same_string(d->dc.model, "manually added dive") &&
|
|
|
|
d->dc.samples == 0) {
|
|
|
|
// so we have depth > 0, a manually added dive and no samples
|
|
|
|
// let's create an actual profile so the desktop version can work it
|
|
|
|
// first clear out the mean depth (or the fake_dc() function tries
|
2018-05-05 17:26:48 +00:00
|
|
|
// to be too clever)
|
2016-02-20 15:33:05 +00:00
|
|
|
d->meandepth.mm = d->dc.meandepth.mm = 0;
|
2018-05-05 17:26:48 +00:00
|
|
|
fake_dc(&d->dc);
|
2016-02-20 15:33:05 +00:00
|
|
|
}
|
2018-04-15 17:05:41 +00:00
|
|
|
fixup_dive(d);
|
2017-04-16 02:06:46 +00:00
|
|
|
DiveListModel::instance()->updateDive(modelIdx, d);
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
invalidate_dive_cache(d);
|
|
|
|
mark_divelist_changed(true);
|
2016-02-20 15:33:05 +00:00
|
|
|
}
|
QML UI: don't immediately save data after we make changes
Much as this felt like the prudent thing to do, it makes the UI painful
to use. In bad network conditions, with a large dive log, on a phone,
the save operation can take more than a minute - which is just completely
ludicrous.
So instead we mark the dive list changed when we make changes and wait
for the app to not be in the foreground. Once the OS tells us that we are
hidden (on the desktop that generally means we don't have focus, on a
mobile device it usually does mean that the app is not on the screen), we
check if there are data to be saved and do so.
There is of course a major problem with this logic. If the user switches
away from Subsurface-mobile but comes back fairly quickly (just reacting
to a notification or briefly checking something, changing a song,
something... then the app may still be non-responsive for quite a while.
So we need to do something about the time it takes us to save the git
tree locally, and then figure out if we can move at least some of the
network traffic to another thread.
And we need to make sure the user immediately notices that the app is not
crashed but is actually saving their data. But that's for another commit.
tl;dr: CAREFUL, don't kill Subsurface-mobile before it had time to save
your data or your changes may be gone. In typical use that shouldn't be
an issue, but it is something that we need to tell the user about.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-04 00:37:17 +00:00
|
|
|
if (diveChanged || needResort)
|
2016-04-11 02:22:16 +00:00
|
|
|
changesNeedSaving();
|
|
|
|
}
|
QML UI: don't immediately save data after we make changes
Much as this felt like the prudent thing to do, it makes the UI painful
to use. In bad network conditions, with a large dive log, on a phone,
the save operation can take more than a minute - which is just completely
ludicrous.
So instead we mark the dive list changed when we make changes and wait
for the app to not be in the foreground. Once the OS tells us that we are
hidden (on the desktop that generally means we don't have focus, on a
mobile device it usually does mean that the app is not on the screen), we
check if there are data to be saved and do so.
There is of course a major problem with this logic. If the user switches
away from Subsurface-mobile but comes back fairly quickly (just reacting
to a notification or briefly checking something, changing a song,
something... then the app may still be non-responsive for quite a while.
So we need to do something about the time it takes us to save the git
tree locally, and then figure out if we can move at least some of the
network traffic to another thread.
And we need to make sure the user immediately notices that the app is not
crashed but is actually saving their data. But that's for another commit.
tl;dr: CAREFUL, don't kill Subsurface-mobile before it had time to save
your data or your changes may be gone. In typical use that shouldn't be
an issue, but it is something that we need to tell the user about.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-04 00:37:17 +00:00
|
|
|
|
2016-04-11 02:22:16 +00:00
|
|
|
void QMLManager::changesNeedSaving()
|
|
|
|
{
|
|
|
|
// we no longer save right away on iOS because file access is so slow; on the other hand,
|
|
|
|
// on Android the save as the user switches away doesn't seem to work... drat.
|
|
|
|
// as a compromise for now we save just to local storage on Android right away (that appears
|
|
|
|
// to be reasonably fast), but don't save at all (and only remember that we need to save things
|
|
|
|
// on iOS
|
|
|
|
// on all other platforms we just save the changes and be done with it
|
|
|
|
mark_divelist_changed(true);
|
2016-04-30 13:21:55 +00:00
|
|
|
#if defined(Q_OS_ANDROID)
|
2016-04-11 02:22:16 +00:00
|
|
|
saveChangesLocal();
|
2016-04-30 13:21:55 +00:00
|
|
|
#elif !defined(Q_OS_IOS)
|
2016-04-11 14:54:22 +00:00
|
|
|
saveChangesCloud(false);
|
2016-04-11 02:22:16 +00:00
|
|
|
#endif
|
2018-01-28 16:39:01 +00:00
|
|
|
updateAllGlobalLists();
|
2015-07-17 15:28:01 +00:00
|
|
|
}
|
mobile: No cloud repo creation more explicit
Before this change, there was only one way to create the local
no cloud repo on the device. The user needed to add at least
one dive to the no cloud account (so that there is something
to save). While this worked in some scenarios, it could also
get things in an inconsistent state: credential status = CS_NOCLOUD
but no local repo. This was a dead end.
In this commit, the creation of the no cloud repo is made more
explicit. When asking for no cloud mode, just create an (empty)
repo for it when it does not yet exist, and otherwise, just
open the existing (possibly empty) repo.
Now, a user can have no cloud repo, next to (any number of)
cloud accounts.
This leaves one functional aspect left: how does a user abandon
the no cloud repo, by merging his data into a true cloud
account. This is code for this, that tries to do this merge in
a smart way. This seems to be broken (too). To be clear: this
is no part of this commit.
Fixes: #667
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2017-10-17 07:51:00 +00:00
|
|
|
|
|
|
|
void QMLManager::openNoCloudRepo()
|
|
|
|
/*
|
|
|
|
* Open the No Cloud repo. In case this repo does not (yet)
|
|
|
|
* exists, create one first. When done, open the repo, which
|
|
|
|
* is obviously empty when just created.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
char *filename = NOCLOUD_LOCALSTORAGE;
|
|
|
|
const char *branch;
|
|
|
|
struct git_repository *git;
|
|
|
|
|
|
|
|
git = is_git_repository(filename, &branch, NULL, false);
|
|
|
|
|
|
|
|
if (git == dummy_git_repository) {
|
2018-01-24 21:56:52 +00:00
|
|
|
git_create_local_repo(filename);
|
2017-12-10 21:22:13 +00:00
|
|
|
set_filename(filename);
|
2019-12-09 18:58:20 +00:00
|
|
|
auto s = qPrefLog::instance();
|
2018-08-12 19:58:25 +00:00
|
|
|
s->set_default_filename(filename);
|
|
|
|
s->set_default_file_behavior(LOCAL_DEFAULT_FILE);
|
mobile: No cloud repo creation more explicit
Before this change, there was only one way to create the local
no cloud repo on the device. The user needed to add at least
one dive to the no cloud account (so that there is something
to save). While this worked in some scenarios, it could also
get things in an inconsistent state: credential status = CS_NOCLOUD
but no local repo. This was a dead end.
In this commit, the creation of the no cloud repo is made more
explicit. When asking for no cloud mode, just create an (empty)
repo for it when it does not yet exist, and otherwise, just
open the existing (possibly empty) repo.
Now, a user can have no cloud repo, next to (any number of)
cloud accounts.
This leaves one functional aspect left: how does a user abandon
the no cloud repo, by merging his data into a true cloud
account. This is code for this, that tries to do this merge in
a smart way. This seems to be broken (too). To be clear: this
is no part of this commit.
Fixes: #667
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2017-10-17 07:51:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
openLocalThenRemote(filename);
|
|
|
|
}
|
|
|
|
|
2016-04-06 18:47:12 +00:00
|
|
|
void QMLManager::saveChangesLocal()
|
2015-07-17 15:28:01 +00:00
|
|
|
{
|
2016-04-06 04:36:56 +00:00
|
|
|
if (unsaved_changes()) {
|
2019-12-28 16:30:14 +00:00
|
|
|
if (qPrefCloudStorage::cloud_verification_status() == qPrefCloudStorage::CS_NOCLOUD) {
|
2018-01-07 10:12:48 +00:00
|
|
|
if (empty_string(existing_filename)) {
|
2016-04-30 13:51:26 +00:00
|
|
|
char *filename = NOCLOUD_LOCALSTORAGE;
|
2018-01-24 21:56:52 +00:00
|
|
|
git_create_local_repo(filename);
|
2017-12-10 21:22:13 +00:00
|
|
|
set_filename(filename);
|
2019-12-09 18:58:20 +00:00
|
|
|
auto s = qPrefLog::instance();
|
2018-08-12 19:58:25 +00:00
|
|
|
s->set_default_filename(filename);
|
|
|
|
s->set_default_file_behavior(LOCAL_DEFAULT_FILE);
|
2016-04-22 14:08:23 +00:00
|
|
|
}
|
2018-01-17 20:15:43 +00:00
|
|
|
} else if (!m_loadFromCloud) {
|
2016-04-06 18:47:12 +00:00
|
|
|
// this seems silly, but you need a common ancestor in the repository in
|
|
|
|
// order to be able to merge che changes later
|
|
|
|
appendTextToLog("Don't save dives without loading from the cloud, first.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (alreadySaving) {
|
|
|
|
appendTextToLog("save operation already in progress, can't save locally");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
alreadySaving = true;
|
2018-09-10 13:30:01 +00:00
|
|
|
bool glo = git_local_only;
|
|
|
|
git_local_only = true;
|
2016-04-06 18:47:12 +00:00
|
|
|
if (save_dives(existing_filename)) {
|
2018-01-24 21:56:52 +00:00
|
|
|
setNotificationText(consumeError());
|
2017-12-10 21:22:13 +00:00
|
|
|
set_filename(NULL);
|
2018-09-10 13:30:01 +00:00
|
|
|
git_local_only = glo;
|
2016-04-06 04:36:56 +00:00
|
|
|
alreadySaving = false;
|
|
|
|
return;
|
|
|
|
}
|
2018-09-10 13:30:01 +00:00
|
|
|
git_local_only = glo;
|
2016-04-06 18:47:12 +00:00
|
|
|
mark_divelist_changed(false);
|
|
|
|
alreadySaving = false;
|
2016-04-06 04:36:56 +00:00
|
|
|
} else {
|
2016-04-06 18:47:12 +00:00
|
|
|
appendTextToLog("local save requested with no unsaved changes");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-08 19:35:45 +00:00
|
|
|
void QMLManager::saveChangesCloud(bool forceRemoteSync)
|
2016-04-06 18:47:12 +00:00
|
|
|
{
|
2016-04-30 17:15:56 +00:00
|
|
|
if (!unsaved_changes() && !forceRemoteSync) {
|
2016-04-15 11:58:09 +00:00
|
|
|
appendTextToLog("asked to save changes but no unsaved changes");
|
2016-04-08 19:35:45 +00:00
|
|
|
return;
|
2016-04-15 11:58:09 +00:00
|
|
|
}
|
2016-04-06 18:47:12 +00:00
|
|
|
if (alreadySaving) {
|
2016-04-15 11:58:09 +00:00
|
|
|
appendTextToLog("save operation in progress already");
|
2016-04-06 18:47:12 +00:00
|
|
|
return;
|
2015-07-17 15:28:01 +00:00
|
|
|
}
|
2016-04-15 11:58:09 +00:00
|
|
|
// first we need to store any unsaved changes to the local repo
|
2017-06-18 06:22:37 +00:00
|
|
|
gitProgressCB("Save changes to local cache");
|
2016-04-15 11:58:09 +00:00
|
|
|
saveChangesLocal();
|
|
|
|
|
|
|
|
// if the user asked not to push to the cloud we are done
|
2018-09-10 13:30:01 +00:00
|
|
|
if (git_local_only && !forceRemoteSync)
|
2016-04-15 11:58:09 +00:00
|
|
|
return;
|
|
|
|
|
2018-01-17 20:15:43 +00:00
|
|
|
if (!m_loadFromCloud) {
|
2019-11-03 14:22:49 +00:00
|
|
|
setNotificationText(tr("Fatal error: cannot save data file. Please copy log file and report."));
|
2016-04-29 13:24:21 +00:00
|
|
|
appendTextToLog("Don't save dives without loading from the cloud, first.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-09-10 13:30:01 +00:00
|
|
|
bool glo = git_local_only;
|
|
|
|
git_local_only = false;
|
2016-04-06 18:47:12 +00:00
|
|
|
alreadySaving = true;
|
2016-04-06 04:36:56 +00:00
|
|
|
loadDivesWithValidCredentials();
|
2016-04-06 18:47:12 +00:00
|
|
|
alreadySaving = false;
|
2018-09-10 13:30:01 +00:00
|
|
|
git_local_only = glo;
|
2015-07-10 08:31:24 +00:00
|
|
|
}
|
2015-08-10 05:35:47 +00:00
|
|
|
|
2016-04-11 19:10:46 +00:00
|
|
|
bool QMLManager::undoDelete(int id)
|
2016-02-29 14:53:26 +00:00
|
|
|
{
|
|
|
|
if (!deletedDive || deletedDive->id != id) {
|
2017-06-18 06:23:41 +00:00
|
|
|
appendTextToLog("Trying to undo delete but can't find the deleted dive");
|
2016-04-11 19:10:46 +00:00
|
|
|
return false;
|
2016-02-29 14:53:26 +00:00
|
|
|
}
|
|
|
|
if (deletedTrip)
|
2018-11-26 22:39:37 +00:00
|
|
|
insert_trip(deletedTrip, &trip_table);
|
2016-02-29 14:53:26 +00:00
|
|
|
if (deletedDive->divetrip) {
|
|
|
|
struct dive_trip *trip = deletedDive->divetrip;
|
|
|
|
deletedDive->divetrip = NULL;
|
|
|
|
add_dive_to_trip(deletedDive, trip);
|
|
|
|
}
|
|
|
|
record_dive(deletedDive);
|
2019-08-13 15:22:15 +00:00
|
|
|
DiveListModel::instance()->insertDive(get_idx_by_uniq_id(deletedDive->id));
|
2016-04-11 02:22:16 +00:00
|
|
|
changesNeedSaving();
|
2016-02-29 14:53:26 +00:00
|
|
|
deletedDive = NULL;
|
|
|
|
deletedTrip = NULL;
|
2016-04-11 19:10:46 +00:00
|
|
|
return true;
|
2016-02-29 14:53:26 +00:00
|
|
|
}
|
|
|
|
|
2019-10-08 03:37:31 +00:00
|
|
|
void QMLManager::selectDive(int id)
|
|
|
|
{
|
|
|
|
int i;
|
2019-10-12 22:30:11 +00:00
|
|
|
extern int amount_selected;
|
2019-10-08 03:37:31 +00:00
|
|
|
struct dive *dive = NULL;
|
|
|
|
|
2019-10-12 22:30:11 +00:00
|
|
|
amount_selected = 0;
|
|
|
|
for_each_dive (i, dive) {
|
2019-10-08 03:37:31 +00:00
|
|
|
dive->selected = (dive->id == id);
|
2019-10-12 22:30:11 +00:00
|
|
|
if (dive->selected)
|
|
|
|
amount_selected++;
|
|
|
|
}
|
|
|
|
if (amount_selected == 0)
|
|
|
|
qWarning("QManager::selectDive() called with unknown id");
|
2019-11-06 06:10:03 +00:00
|
|
|
else
|
|
|
|
CollapsedDiveListSortModel::instance()->updateSelectionState();
|
2019-10-08 03:37:31 +00:00
|
|
|
}
|
|
|
|
|
2016-02-23 12:39:40 +00:00
|
|
|
void QMLManager::deleteDive(int id)
|
|
|
|
{
|
|
|
|
struct dive *d = get_dive_by_uniq_id(id);
|
|
|
|
if (!d) {
|
2017-06-18 06:23:41 +00:00
|
|
|
appendTextToLog("trying to delete non-existing dive");
|
2016-02-23 12:39:40 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-09-29 12:58:04 +00:00
|
|
|
// create the storage for the deleted dive and trip (if applicable)
|
2016-02-29 14:53:26 +00:00
|
|
|
if (!deletedDive)
|
|
|
|
deletedDive = alloc_dive();
|
|
|
|
copy_dive(d, deletedDive);
|
|
|
|
if (!deletedTrip) {
|
2018-09-23 19:22:48 +00:00
|
|
|
deletedTrip = alloc_trip();
|
2016-02-29 14:53:26 +00:00
|
|
|
} else {
|
|
|
|
free(deletedTrip->location);
|
|
|
|
free(deletedTrip->notes);
|
|
|
|
memset(deletedTrip, 0, sizeof(struct dive_trip));
|
|
|
|
}
|
|
|
|
// if this is the last dive in that trip, remember the trip as well
|
2018-11-08 15:58:33 +00:00
|
|
|
if (d->divetrip && d->divetrip->dives.nr == 1) {
|
2016-02-29 14:53:26 +00:00
|
|
|
*deletedTrip = *d->divetrip;
|
|
|
|
deletedTrip->location = copy_string(d->divetrip->location);
|
|
|
|
deletedTrip->notes = copy_string(d->divetrip->notes);
|
2018-11-08 15:58:33 +00:00
|
|
|
deletedTrip->dives.nr = 0;
|
2016-02-29 14:53:26 +00:00
|
|
|
deletedDive->divetrip = deletedTrip;
|
|
|
|
}
|
2016-02-23 12:39:40 +00:00
|
|
|
DiveListModel::instance()->removeDiveById(id);
|
|
|
|
delete_single_dive(get_idx_by_uniq_id(id));
|
2018-01-07 15:08:25 +00:00
|
|
|
DiveListModel::instance()->resetInternalData();
|
2016-04-11 02:22:16 +00:00
|
|
|
changesNeedSaving();
|
2016-02-23 12:39:40 +00:00
|
|
|
}
|
|
|
|
|
2018-11-18 05:42:15 +00:00
|
|
|
bool QMLManager::toggleDiveSite(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
what.divesite = what.divesite ? false : true;
|
|
|
|
|
|
|
|
return what.divesite;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::toggleNotes(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
what.notes = what.notes ? false : true;
|
|
|
|
|
|
|
|
return what.notes;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::toggleDiveMaster(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
what.divemaster = what.divemaster ? false : true;
|
|
|
|
|
|
|
|
return what.divemaster;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::toggleBuddy(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
what.buddy = what.buddy ? false : true;
|
|
|
|
|
|
|
|
return what.buddy;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::toggleSuit(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
what.suit = what.suit ? false : true;
|
|
|
|
|
|
|
|
return what.suit;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::toggleRating(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
what.rating = what.rating ? false : true;
|
|
|
|
|
|
|
|
return what.rating;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::toggleVisibility(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
what.visibility = what.visibility ? false : true;
|
|
|
|
|
|
|
|
return what.visibility;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::toggleTags(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
what.tags = what.tags ? false : true;
|
|
|
|
|
|
|
|
return what.tags;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::toggleCylinders(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
what.cylinders = what.cylinders ? false : true;
|
|
|
|
|
|
|
|
return what.cylinders;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::toggleWeights(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
what.weights = what.weights ? false : true;
|
|
|
|
|
|
|
|
return what.weights;
|
|
|
|
}
|
|
|
|
|
2018-10-27 07:21:40 +00:00
|
|
|
void QMLManager::copyDiveData(int id)
|
|
|
|
{
|
|
|
|
m_copyPasteDive = get_dive_by_uniq_id(id);
|
|
|
|
if (!m_copyPasteDive) {
|
|
|
|
appendTextToLog("trying to copy non-existing dive");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-04 05:10:35 +00:00
|
|
|
setNotificationText("Copy");
|
2018-10-27 07:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::pasteDiveData(int id)
|
|
|
|
{
|
|
|
|
struct dive *d = get_dive_by_uniq_id(id);
|
|
|
|
if (!d) {
|
|
|
|
appendTextToLog("trying to paste to non-existing dive");
|
|
|
|
return;
|
|
|
|
}
|
2018-10-27 09:00:12 +00:00
|
|
|
if (!m_copyPasteDive) {
|
|
|
|
appendTextToLog("dive to paste is not selected");
|
|
|
|
return;
|
|
|
|
}
|
2018-10-27 07:21:40 +00:00
|
|
|
selective_copy_dive(m_copyPasteDive, d, what, false);
|
2018-10-29 15:58:05 +00:00
|
|
|
|
|
|
|
invalidate_dive_cache(d);
|
|
|
|
mark_divelist_changed(true);
|
2018-10-27 07:21:40 +00:00
|
|
|
changesNeedSaving();
|
2018-11-04 05:10:35 +00:00
|
|
|
setNotificationText("Paste");
|
2018-12-16 09:34:05 +00:00
|
|
|
|
|
|
|
int modelIdx = DiveListModel::instance()->getDiveIdx(id);
|
|
|
|
DiveListModel::instance()->updateDive(modelIdx, d);
|
2018-10-27 07:21:40 +00:00
|
|
|
}
|
|
|
|
|
2017-07-19 07:16:47 +00:00
|
|
|
void QMLManager::cancelDownloadDC()
|
|
|
|
{
|
|
|
|
import_thread_cancelled = true;
|
|
|
|
}
|
|
|
|
|
2015-12-27 05:37:18 +00:00
|
|
|
QString QMLManager::addDive()
|
2015-08-10 05:35:47 +00:00
|
|
|
{
|
2015-08-19 07:17:52 +00:00
|
|
|
appendTextToLog("Adding new dive.");
|
2015-12-27 05:37:18 +00:00
|
|
|
return DiveListModel::instance()->startAddDive();
|
2015-08-10 05:35:47 +00:00
|
|
|
}
|
|
|
|
|
2016-01-29 14:25:13 +00:00
|
|
|
void QMLManager::addDiveAborted(int id)
|
|
|
|
{
|
|
|
|
DiveListModel::instance()->removeDiveById(id);
|
2017-12-15 20:51:24 +00:00
|
|
|
delete_single_dive(get_idx_by_uniq_id(id));
|
2016-01-29 14:25:13 +00:00
|
|
|
}
|
|
|
|
|
2016-01-02 01:23:29 +00:00
|
|
|
QString QMLManager::getCurrentPosition()
|
|
|
|
{
|
2016-04-18 05:54:53 +00:00
|
|
|
static bool hasLocationSource = false;
|
|
|
|
if (locationProvider->hasLocationsSource() != hasLocationSource) {
|
|
|
|
hasLocationSource = !hasLocationSource;
|
|
|
|
setLocationServiceAvailable(hasLocationSource);
|
|
|
|
}
|
|
|
|
if (!hasLocationSource)
|
|
|
|
return tr("Unknown GPS location");
|
|
|
|
|
2018-04-14 18:12:07 +00:00
|
|
|
QString positionResponse = locationProvider->currentPosition();
|
|
|
|
if (positionResponse == GPS_CURRENT_POS)
|
|
|
|
connect(locationProvider, &GpsLocation::acquiredPosition, this, &QMLManager::waitingForPositionChanged, Qt::UniqueConnection);
|
|
|
|
else
|
|
|
|
disconnect(locationProvider, &GpsLocation::acquiredPosition, this, &QMLManager::waitingForPositionChanged);
|
|
|
|
return positionResponse;
|
2016-01-02 01:23:29 +00:00
|
|
|
}
|
|
|
|
|
2015-11-13 04:23:00 +00:00
|
|
|
void QMLManager::applyGpsData()
|
|
|
|
{
|
2019-10-23 01:57:02 +00:00
|
|
|
appendTextToLog("Applying GPS fiexs");
|
|
|
|
int cnt = locationProvider->applyLocations();
|
|
|
|
if (cnt == 0)
|
|
|
|
return;
|
|
|
|
appendTextToLog(QString("Attached %1 GPS fixes").arg(cnt));
|
|
|
|
refreshDiveList();
|
2015-11-13 04:23:00 +00:00
|
|
|
}
|
|
|
|
|
2016-01-08 05:40:15 +00:00
|
|
|
void QMLManager::populateGpsData()
|
|
|
|
{
|
2016-01-08 15:11:49 +00:00
|
|
|
if (GpsListModel::instance())
|
2019-09-27 23:26:54 +00:00
|
|
|
GpsListModel::instance()->update();
|
2016-01-08 05:40:15 +00:00
|
|
|
}
|
|
|
|
|
2015-11-14 01:20:45 +00:00
|
|
|
void QMLManager::clearGpsData()
|
|
|
|
{
|
|
|
|
locationProvider->clearGpsData();
|
2016-01-08 15:11:49 +00:00
|
|
|
populateGpsData();
|
2015-11-14 01:20:45 +00:00
|
|
|
}
|
|
|
|
|
2016-01-09 07:18:41 +00:00
|
|
|
void QMLManager::deleteGpsFix(quint64 when)
|
|
|
|
{
|
|
|
|
locationProvider->deleteGpsFix(when);
|
|
|
|
populateGpsData();
|
|
|
|
}
|
|
|
|
|
2015-08-19 07:17:52 +00:00
|
|
|
QString QMLManager::logText() const
|
|
|
|
{
|
2015-11-13 17:17:13 +00:00
|
|
|
QString logText = m_logText + QString("\nNumer of GPS fixes: %1").arg(locationProvider->getGpsNum());
|
|
|
|
return logText;
|
2015-08-19 07:17:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::setLogText(const QString &logText)
|
|
|
|
{
|
|
|
|
m_logText = logText;
|
2015-08-20 09:08:59 +00:00
|
|
|
emit logTextChanged();
|
2015-08-19 07:17:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::appendTextToLog(const QString &newText)
|
|
|
|
{
|
2017-06-06 06:22:19 +00:00
|
|
|
qDebug() << QString::number(timer.elapsed() / 1000.0,'f', 3) + ": " + newText;
|
2015-08-19 07:17:52 +00:00
|
|
|
}
|
|
|
|
|
2015-11-11 20:34:56 +00:00
|
|
|
void QMLManager::setLocationServiceEnabled(bool locationServiceEnabled)
|
|
|
|
{
|
|
|
|
m_locationServiceEnabled = locationServiceEnabled;
|
|
|
|
locationProvider->serviceEnable(m_locationServiceEnabled);
|
2017-07-23 07:38:40 +00:00
|
|
|
emit locationServiceEnabledChanged();
|
2015-11-11 20:34:56 +00:00
|
|
|
}
|
2015-07-10 08:31:24 +00:00
|
|
|
|
2016-04-18 05:54:53 +00:00
|
|
|
void QMLManager::setLocationServiceAvailable(bool locationServiceAvailable)
|
|
|
|
{
|
2017-06-18 06:23:41 +00:00
|
|
|
appendTextToLog(QStringLiteral("location service is ") + (locationServiceAvailable ? QStringLiteral("available") : QStringLiteral("not available")));
|
2016-04-18 05:54:53 +00:00
|
|
|
m_locationServiceAvailable = locationServiceAvailable;
|
|
|
|
emit locationServiceAvailableChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::hasLocationSourceChanged()
|
|
|
|
{
|
|
|
|
setLocationServiceAvailable(locationProvider->hasLocationsSource());
|
|
|
|
}
|
|
|
|
|
2015-12-20 02:41:10 +00:00
|
|
|
void QMLManager::setVerboseEnabled(bool verboseMode)
|
|
|
|
{
|
|
|
|
m_verboseEnabled = verboseMode;
|
|
|
|
verbose = verboseMode;
|
2017-06-18 06:23:41 +00:00
|
|
|
appendTextToLog(QStringLiteral("verbose is ") + (verbose ? QStringLiteral("on") : QStringLiteral("off")));
|
2015-12-20 02:41:10 +00:00
|
|
|
emit verboseEnabledChanged();
|
|
|
|
}
|
|
|
|
|
2016-02-08 19:08:49 +00:00
|
|
|
void QMLManager::syncLoadFromCloud()
|
|
|
|
{
|
2018-09-04 17:02:26 +00:00
|
|
|
QSettings s;
|
2020-01-27 00:49:42 +00:00
|
|
|
QString cloudMarker = QLatin1String("loadFromCloud") + QString(prefs.cloud_storage_email);
|
2018-09-04 17:02:26 +00:00
|
|
|
m_loadFromCloud = s.contains(cloudMarker) && s.value(cloudMarker).toBool();
|
2016-02-08 19:08:49 +00:00
|
|
|
}
|
|
|
|
|
2015-12-03 02:49:02 +00:00
|
|
|
void QMLManager::setLoadFromCloud(bool done)
|
|
|
|
{
|
2018-09-04 17:02:26 +00:00
|
|
|
QSettings s;
|
2020-01-27 00:49:42 +00:00
|
|
|
QString cloudMarker = QLatin1String("loadFromCloud") + QString(prefs.cloud_storage_email);
|
2018-09-04 17:02:26 +00:00
|
|
|
s.setValue(cloudMarker, done);
|
2015-12-03 02:49:02 +00:00
|
|
|
m_loadFromCloud = done;
|
|
|
|
emit loadFromCloudChanged();
|
|
|
|
}
|
2015-12-15 07:00:19 +00:00
|
|
|
|
2016-01-26 15:02:42 +00:00
|
|
|
void QMLManager::setStartPageText(const QString& text)
|
2015-12-15 07:00:19 +00:00
|
|
|
{
|
|
|
|
m_startPageText = text;
|
|
|
|
emit startPageTextChanged();
|
|
|
|
}
|
2015-12-26 21:22:50 +00:00
|
|
|
|
2016-01-26 15:02:42 +00:00
|
|
|
QString QMLManager::getNumber(const QString& diveId)
|
2015-12-27 04:02:23 +00:00
|
|
|
{
|
|
|
|
int dive_id = diveId.toInt();
|
|
|
|
struct dive *d = get_dive_by_uniq_id(dive_id);
|
|
|
|
QString number;
|
|
|
|
if (d)
|
|
|
|
number = QString::number(d->number);
|
|
|
|
return number;
|
|
|
|
}
|
|
|
|
|
2016-01-26 15:02:42 +00:00
|
|
|
QString QMLManager::getDate(const QString& diveId)
|
2015-12-27 04:02:23 +00:00
|
|
|
{
|
|
|
|
int dive_id = diveId.toInt();
|
|
|
|
struct dive *d = get_dive_by_uniq_id(dive_id);
|
|
|
|
QString datestring;
|
|
|
|
if (d)
|
2017-12-17 08:02:48 +00:00
|
|
|
datestring = get_short_dive_date_string(d->when);
|
2015-12-27 04:02:23 +00:00
|
|
|
return datestring;
|
|
|
|
}
|
2016-02-10 20:53:58 +00:00
|
|
|
|
|
|
|
QString QMLManager::getVersion() const
|
|
|
|
{
|
2016-03-05 20:53:38 +00:00
|
|
|
QRegExp versionRe(".*:([()\\.,\\d]+).*");
|
2016-02-10 20:53:58 +00:00
|
|
|
if (!versionRe.exactMatch(getUserAgent()))
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
return versionRe.cap(1);
|
|
|
|
}
|
2016-03-03 01:13:42 +00:00
|
|
|
|
2019-02-26 21:26:11 +00:00
|
|
|
QString QMLManager::getGpsFromSiteName(const QString &siteName)
|
2018-10-23 10:42:01 +00:00
|
|
|
{
|
2017-11-22 18:22:02 +00:00
|
|
|
struct dive_site *ds;
|
|
|
|
|
2019-02-26 21:26:11 +00:00
|
|
|
ds = get_dive_site_by_name(qPrintable(siteName), &dive_site_table);
|
2019-03-24 20:50:01 +00:00
|
|
|
if (!ds)
|
|
|
|
return QString();
|
2019-03-25 08:05:47 +00:00
|
|
|
return printGPSCoords(&ds->location);
|
2017-11-22 18:22:02 +00:00
|
|
|
}
|
|
|
|
|
2017-06-18 06:22:37 +00:00
|
|
|
void QMLManager::setNotificationText(QString text)
|
2016-03-03 01:13:42 +00:00
|
|
|
{
|
2017-06-18 06:22:37 +00:00
|
|
|
m_notificationText = text;
|
|
|
|
emit notificationTextChanged();
|
2016-03-03 01:13:42 +00:00
|
|
|
}
|
2016-03-09 03:31:05 +00:00
|
|
|
|
2016-04-14 13:01:36 +00:00
|
|
|
void QMLManager::setUpdateSelectedDive(int idx)
|
|
|
|
{
|
|
|
|
m_updateSelectedDive = idx;
|
|
|
|
emit updateSelectedDiveChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::setSelectedDiveTimestamp(int when)
|
|
|
|
{
|
|
|
|
m_selectedDiveTimestamp = when;
|
|
|
|
emit selectedDiveTimestampChanged();
|
|
|
|
}
|
|
|
|
|
2016-03-09 03:31:05 +00:00
|
|
|
qreal QMLManager::lastDevicePixelRatio()
|
|
|
|
{
|
|
|
|
return m_lastDevicePixelRatio;
|
|
|
|
}
|
|
|
|
|
2017-04-04 00:29:06 +00:00
|
|
|
void QMLManager::setDevicePixelRatio(qreal dpr, QScreen *screen)
|
|
|
|
{
|
|
|
|
if (m_lastDevicePixelRatio != dpr) {
|
|
|
|
m_lastDevicePixelRatio = dpr;
|
|
|
|
emit sendScreenChanged(screen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-09 03:31:05 +00:00
|
|
|
void QMLManager::screenChanged(QScreen *screen)
|
|
|
|
{
|
2019-09-28 19:04:52 +00:00
|
|
|
qDebug("QMLManager received screen changed notification (%d,%d)", screen->size().width(), screen->size().height());
|
2016-03-09 03:31:05 +00:00
|
|
|
m_lastDevicePixelRatio = screen->devicePixelRatio();
|
|
|
|
emit sendScreenChanged(screen);
|
|
|
|
}
|
2016-04-15 21:42:08 +00:00
|
|
|
|
|
|
|
void QMLManager::quit()
|
|
|
|
{
|
|
|
|
if (unsaved_changes())
|
|
|
|
saveChangesCloud(false);
|
|
|
|
QApplication::quit();
|
|
|
|
}
|
2016-05-20 16:48:35 +00:00
|
|
|
|
2018-01-28 08:52:51 +00:00
|
|
|
QStringList QMLManager::suitList() const
|
2016-05-20 16:48:35 +00:00
|
|
|
{
|
2018-01-28 08:52:51 +00:00
|
|
|
return suitModel.stringList();
|
2016-05-20 16:48:35 +00:00
|
|
|
}
|
|
|
|
|
2018-01-28 09:26:45 +00:00
|
|
|
QStringList QMLManager::buddyList() const
|
2016-05-20 16:48:35 +00:00
|
|
|
{
|
2018-01-28 09:26:45 +00:00
|
|
|
return buddyModel.stringList();
|
2016-05-20 16:48:35 +00:00
|
|
|
}
|
|
|
|
|
2018-01-28 10:28:01 +00:00
|
|
|
QStringList QMLManager::divemasterList() const
|
2016-05-20 16:48:35 +00:00
|
|
|
{
|
2018-01-28 10:28:01 +00:00
|
|
|
return divemasterModel.stringList();
|
2016-05-20 16:48:35 +00:00
|
|
|
}
|
2016-06-13 23:41:26 +00:00
|
|
|
|
2018-01-28 14:21:28 +00:00
|
|
|
QStringList QMLManager::locationList() const
|
|
|
|
{
|
|
|
|
return locationModel.allSiteNames();
|
|
|
|
}
|
|
|
|
|
2017-04-15 00:32:32 +00:00
|
|
|
QStringList QMLManager::cylinderInit() const
|
|
|
|
{
|
|
|
|
QStringList cylinders;
|
|
|
|
struct dive *d;
|
|
|
|
int i = 0;
|
|
|
|
for_each_dive (i, d) {
|
2019-08-04 16:44:57 +00:00
|
|
|
for (int j = 0; j < d->cylinders.nr; j++) {
|
2019-08-04 20:13:49 +00:00
|
|
|
if (!empty_string(get_cylinder(d, j)->type.description))
|
|
|
|
cylinders << get_cylinder(d, j)->type.description;
|
2017-04-15 00:32:32 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-28 15:45:01 +00:00
|
|
|
|
|
|
|
for (unsigned long ti = 0; ti < MAX_TANK_INFO && tank_info[ti].name != NULL; ti++) {
|
|
|
|
QString cyl = tank_info[ti].name;
|
|
|
|
if (cyl == "")
|
|
|
|
continue;
|
|
|
|
cylinders << cyl;
|
|
|
|
}
|
|
|
|
|
2017-04-15 00:32:32 +00:00
|
|
|
cylinders.removeDuplicates();
|
|
|
|
cylinders.sort();
|
2020-01-20 17:29:05 +00:00
|
|
|
// now add fist one that indicates that the user wants no default cylinder
|
|
|
|
cylinders.prepend(tr("no default cylinder"));
|
2017-04-15 00:32:32 +00:00
|
|
|
return cylinders;
|
|
|
|
}
|
|
|
|
|
2017-07-09 22:07:16 +00:00
|
|
|
void QMLManager::setProgressMessage(QString text)
|
|
|
|
{
|
|
|
|
m_progressMessage = text;
|
|
|
|
emit progressMessageChanged();
|
|
|
|
}
|
|
|
|
|
2017-10-12 07:43:40 +00:00
|
|
|
void QMLManager::setBtEnabled(bool value)
|
|
|
|
{
|
|
|
|
m_btEnabled = value;
|
|
|
|
}
|
|
|
|
|
2018-04-13 23:53:51 +00:00
|
|
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
2017-06-23 14:31:44 +00:00
|
|
|
|
2017-07-10 00:03:57 +00:00
|
|
|
void writeToAppLogFile(QString logText)
|
|
|
|
{
|
|
|
|
// write to storage and flush so that the data doesn't get lost
|
|
|
|
logText.append("\n");
|
|
|
|
QMLManager *self = QMLManager::instance();
|
|
|
|
if (self) {
|
|
|
|
self->writeToAppLogFile(logText);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::writeToAppLogFile(QString logText)
|
|
|
|
{
|
|
|
|
if (appLogFileOpen) {
|
2018-02-25 12:51:41 +00:00
|
|
|
appLogFile.write(qPrintable(logText));
|
2017-07-10 00:03:57 +00:00
|
|
|
appLogFile.flush();
|
|
|
|
}
|
|
|
|
}
|
2018-04-13 23:53:51 +00:00
|
|
|
#endif
|
2017-06-23 14:31:44 +00:00
|
|
|
|
2018-04-13 23:53:51 +00:00
|
|
|
#if defined(Q_OS_ANDROID)
|
2017-06-23 14:31:44 +00:00
|
|
|
//HACK to color the system bar on Android, use qtandroidextras and call the appropriate Java methods
|
|
|
|
//this code is based on code in the Kirigami example app for Android (under LGPL-2) Copyright 2017 Marco Martin
|
|
|
|
|
|
|
|
#include <QtAndroid>
|
|
|
|
|
|
|
|
// there doesn't appear to be an include that defines these in an easily accessible way
|
|
|
|
// WindowManager.LayoutParams
|
|
|
|
#define FLAG_TRANSLUCENT_STATUS 0x04000000
|
|
|
|
#define FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 0x80000000
|
|
|
|
// View
|
|
|
|
#define SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 0x00002000
|
|
|
|
|
|
|
|
void QMLManager::setStatusbarColor(QColor color)
|
|
|
|
{
|
2020-02-04 13:09:12 +00:00
|
|
|
QtAndroid::runOnAndroidThread([color]() {
|
2017-06-23 14:31:44 +00:00
|
|
|
QAndroidJniObject window = QtAndroid::androidActivity().callObjectMethod("getWindow", "()Landroid/view/Window;");
|
|
|
|
window.callMethod<void>("addFlags", "(I)V", FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
|
|
|
window.callMethod<void>("clearFlags", "(I)V", FLAG_TRANSLUCENT_STATUS);
|
|
|
|
window.callMethod<void>("setStatusBarColor", "(I)V", color.rgba());
|
|
|
|
window.callMethod<void>("setNavigationBarColor", "(I)V", color.rgba());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
#else
|
2018-05-21 15:22:34 +00:00
|
|
|
void QMLManager::setStatusbarColor(QColor)
|
2017-06-23 14:31:44 +00:00
|
|
|
{
|
|
|
|
// noop
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2018-06-09 11:14:54 +00:00
|
|
|
|
2018-12-21 22:52:02 +00:00
|
|
|
void QMLManager::retrieveBluetoothName()
|
|
|
|
{
|
|
|
|
QString name = DC_devName();
|
2019-04-01 20:15:19 +00:00
|
|
|
const QList<BTDiscovery::btVendorProduct> btDCs = BTDiscovery::instance()->getBtDcs();
|
|
|
|
for (BTDiscovery::btVendorProduct btDC: btDCs) {
|
2018-12-21 22:52:02 +00:00
|
|
|
qDebug() << "compare" <<name << btDC.btpdi.address;
|
|
|
|
if (name.contains(btDC.btpdi.address))
|
|
|
|
DC_setDevBluetoothName(btDC.btpdi.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-09 11:14:54 +00:00
|
|
|
QString QMLManager::DC_vendor() const
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->vendor();
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString QMLManager::DC_product() const
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->product();
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString QMLManager::DC_devName() const
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->devName();
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString QMLManager::DC_devBluetoothName() const
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->devBluetoothName();
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString QMLManager::DC_descriptor() const
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->descriptor();
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::DC_forceDownload() const
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->forceDownload();
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::DC_bluetoothMode() const
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->bluetoothMode();
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool QMLManager::DC_saveDump() const
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->saveDump();
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int QMLManager::DC_deviceId() const
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->deviceId();
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::DC_setDeviceId(int deviceId)
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
DCDeviceData::instance()->setDeviceId(deviceId);
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::DC_setVendor(const QString& vendor)
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
DCDeviceData::instance()->setVendor(vendor);
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::DC_setProduct(const QString& product)
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
DCDeviceData::instance()->setProduct(product);
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::DC_setDevName(const QString& devName)
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
DCDeviceData::instance()->setDevName(devName);
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::DC_setDevBluetoothName(const QString& devBluetoothName)
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
DCDeviceData::instance()->setDevBluetoothName(devBluetoothName);
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::DC_setBluetoothMode(bool mode)
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
DCDeviceData::instance()->setBluetoothMode(mode);
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::DC_setForceDownload(bool force)
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
DCDeviceData::instance()->setForceDownload(force);
|
2019-09-21 23:31:27 +00:00
|
|
|
DC_ForceDownloadChanged();
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::DC_setSaveDump(bool dumpMode)
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
DCDeviceData::instance()->setSaveDump(dumpMode);
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QStringList QMLManager::getProductListFromVendor(const QString &vendor)
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->getProductListFromVendor(vendor);
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int QMLManager::getMatchingAddress(const QString &vendor, const QString &product)
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->getMatchingAddress(vendor, product);
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int QMLManager::getDetectedVendorIndex()
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->getDetectedVendorIndex();
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int QMLManager::getDetectedProductIndex(const QString ¤tVendorText)
|
|
|
|
{
|
2018-12-10 14:21:50 +00:00
|
|
|
return DCDeviceData::instance()->getDetectedProductIndex(currentVendorText);
|
2018-06-09 11:14:54 +00:00
|
|
|
}
|
2018-08-07 01:29:27 +00:00
|
|
|
|
2018-09-23 05:53:43 +00:00
|
|
|
int QMLManager::getConnectionIndex(const QString &deviceSubstr)
|
|
|
|
{
|
|
|
|
return connectionListModel.indexOf(deviceSubstr);
|
|
|
|
}
|
|
|
|
|
2018-10-09 08:23:24 +00:00
|
|
|
void QMLManager::setGitLocalOnly(const bool &value)
|
|
|
|
{
|
|
|
|
git_local_only = value;
|
|
|
|
}
|
|
|
|
|
2018-08-07 01:29:27 +00:00
|
|
|
void QMLManager::showDownloadPage(QString deviceString)
|
|
|
|
{
|
2018-08-09 03:34:39 +00:00
|
|
|
// we pass the indices for the three combo boxes for vendor, product, and connection
|
|
|
|
// to the QML UI
|
|
|
|
// for each of these values '-1' means that no entry should be pre-selected
|
|
|
|
QString name("-1;-1;-1");
|
|
|
|
|
|
|
|
// try to guess the dive computer (or at least vendor) from the string that
|
|
|
|
// we get from the Intent
|
|
|
|
// the first couple we do text based because we know exactly what to look for,
|
|
|
|
// the rest is based on the vendor and product IDs
|
2018-08-11 02:39:37 +00:00
|
|
|
if (deviceString.contains("HeinrichsWeikamp OSTC3")) {
|
2018-08-09 03:34:39 +00:00
|
|
|
name = QString("%1;%2;%3")
|
2020-01-27 00:51:01 +00:00
|
|
|
.arg(vendorList.indexOf("Heinrichs Weikamp"))
|
|
|
|
.arg(productList["Heinrichs Weikamp"].indexOf("OSTC 3"))
|
2020-03-08 04:12:06 +00:00
|
|
|
.arg(connectionListModel.indexOf("usb-serial"));
|
2018-08-11 18:28:03 +00:00
|
|
|
} else if (deviceString.contains("HeinrichsWeikamp OSTC 2N")) {
|
2020-01-27 00:51:01 +00:00
|
|
|
name = QString("%1;%2;%3")
|
|
|
|
.arg(vendorList.indexOf("Heinrichs Weikamp"))
|
|
|
|
.arg(productList["Heinrichs Weikamp"].indexOf("OSTC 2N"))
|
2020-03-08 04:12:06 +00:00
|
|
|
.arg(connectionListModel.indexOf("usb-serial"));
|
2018-08-09 03:34:39 +00:00
|
|
|
} else if (deviceString.contains("mManufacturerName=ATOMIC AQUATICS") &&
|
2020-01-27 00:51:01 +00:00
|
|
|
deviceString.contains("mProductName=COBALT")) {
|
2018-08-11 04:43:50 +00:00
|
|
|
if (deviceString.contains("mVersion=2")) {
|
2018-08-09 03:34:39 +00:00
|
|
|
name = QString("%1;%2;%3")
|
2020-01-27 00:51:01 +00:00
|
|
|
.arg(vendorList.indexOf("Atomic Aquatics"))
|
|
|
|
.arg(productList["Atomic Aquatics"].indexOf("Cobalt 2"))
|
|
|
|
.arg(connectionListModel.indexOf("USB device"));
|
2018-08-11 04:43:50 +00:00
|
|
|
} else {
|
2018-08-09 03:34:39 +00:00
|
|
|
name = QString("%1;%2;%3")
|
2020-01-27 00:51:01 +00:00
|
|
|
.arg(vendorList.indexOf("Atomic Aquatics"))
|
|
|
|
.arg(productList["Atomic Aquatics"].indexOf("Cobalt"))
|
|
|
|
.arg(connectionListModel.indexOf("USB device"));
|
2018-08-11 04:43:50 +00:00
|
|
|
}
|
2018-08-11 19:20:21 +00:00
|
|
|
} else if (deviceString.contains("mVendorId=5267") && // 0x1493 / 0x0030
|
2020-01-27 00:51:01 +00:00
|
|
|
deviceString.contains("mProductId=48")) {
|
2018-08-09 03:34:39 +00:00
|
|
|
name = QString("%1;%2;%3")
|
2020-01-27 00:51:01 +00:00
|
|
|
.arg(connectionListModel.indexOf("Suunto"))
|
|
|
|
.arg(productList["Suunto"].indexOf("EON Steel"))
|
|
|
|
.arg(connectionListModel.indexOf("USB device"));
|
2018-08-11 19:20:21 +00:00
|
|
|
} else if (deviceString.contains("mVendorId=5267") && // 0x1493 / 0x0033
|
2020-01-27 00:51:01 +00:00
|
|
|
deviceString.contains("mProductId=51")) {
|
2018-08-09 03:34:39 +00:00
|
|
|
name = QString("%1;%2;%3")
|
2020-01-27 00:51:01 +00:00
|
|
|
.arg(connectionListModel.indexOf("Suunto"))
|
|
|
|
.arg(productList["Suunto"].indexOf("EON Core"))
|
|
|
|
.arg(connectionListModel.indexOf("USB device"));
|
2019-04-24 16:15:41 +00:00
|
|
|
} else if (deviceString.contains("mVendorId=11884") && // 0x2e6c / 0x3201,0x3211,0x4201
|
2020-01-27 00:51:01 +00:00
|
|
|
(deviceString.contains("mProductId=12801") ||
|
|
|
|
deviceString.contains("mProductId=12817") ||
|
|
|
|
deviceString.contains("mProductId=16897"))) {
|
2018-08-09 03:34:39 +00:00
|
|
|
name = QString("%1;%2;%3")
|
2020-01-27 00:51:01 +00:00
|
|
|
.arg(connectionListModel.indexOf("Scubapro"))
|
|
|
|
.arg(productList["Scubapro"].indexOf("G2"))
|
|
|
|
.arg(connectionListModel.indexOf("USB device"));
|
2018-08-11 19:20:21 +00:00
|
|
|
} else if (deviceString.contains("mVendorId=49745") && // 0xc251 / 0x2006
|
2020-01-27 00:51:01 +00:00
|
|
|
deviceString.contains("mProductId=8198")) {
|
2018-08-09 03:34:39 +00:00
|
|
|
name = QString("%1;%2;%3")
|
2020-01-27 00:51:01 +00:00
|
|
|
.arg(connectionListModel.indexOf("Scubapro"))
|
|
|
|
.arg(productList["Scubapro"].indexOf("Aladin Square"))
|
|
|
|
.arg(connectionListModel.indexOf("USB device"));
|
2020-03-08 04:12:06 +00:00
|
|
|
} else if (deviceString.contains("mVendorId=1027") && // FTDI: 0x0403 / 0x6001,0x6010,0x6011,0x6014,0x6015
|
2020-01-27 00:51:01 +00:00
|
|
|
(deviceString.contains("mProductId=24577") ||
|
|
|
|
deviceString.contains("mProductId=24592") ||
|
|
|
|
deviceString.contains("mProductId=24593") ||
|
2020-03-08 04:12:06 +00:00
|
|
|
deviceString.contains("mProductId=24596") ||
|
2020-01-27 00:51:01 +00:00
|
|
|
deviceString.contains("mProductId=24597"))) {
|
2020-03-08 04:12:06 +00:00
|
|
|
name = QString("-1;-1;%1").arg(connectionListModel.indexOf("usb-serial"));
|
2018-08-11 19:20:21 +00:00
|
|
|
} else if (deviceString.contains("mVendorId=1027") && // 0x0403 / 0xf460
|
2020-01-27 00:51:01 +00:00
|
|
|
deviceString.contains("mProductId=62560")) {
|
2018-08-09 03:34:39 +00:00
|
|
|
name = QString("%1;-1;%2")
|
2020-01-27 00:51:01 +00:00
|
|
|
.arg(vendorList.indexOf("Oceanic"))
|
2020-03-08 04:12:06 +00:00
|
|
|
.arg(connectionListModel.indexOf("usb-serial"));
|
2018-08-11 19:20:21 +00:00
|
|
|
} else if (deviceString.contains("mVendorId=1027") && // 0x0403 / 0xf680
|
2020-01-27 00:51:01 +00:00
|
|
|
deviceString.contains("mProductId=63104")) {
|
2018-08-09 03:34:39 +00:00
|
|
|
name = QString("%1;-1;%2")
|
2020-01-27 00:51:01 +00:00
|
|
|
.arg(vendorList.indexOf("Suunto"))
|
2020-03-08 04:12:06 +00:00
|
|
|
.arg(connectionListModel.indexOf("usb-serial"));
|
2018-08-11 19:20:21 +00:00
|
|
|
} else if (deviceString.contains("mVendorId=1027") && // 0x0403 / 0x87d0
|
2020-01-27 00:51:01 +00:00
|
|
|
deviceString.contains("mProductId=34768")) {
|
2018-08-09 03:34:39 +00:00
|
|
|
name = QString("%1;-1;%2")
|
2020-01-27 00:51:01 +00:00
|
|
|
.arg(vendorList.indexOf("Cressi"))
|
2020-03-08 04:12:06 +00:00
|
|
|
.arg(connectionListModel.indexOf("usb-serial"));
|
|
|
|
} else if (deviceString.contains("mVendorId=65535") && // 0xffff / 0x0005
|
|
|
|
deviceString.contains("mProductId=5")) {
|
|
|
|
name = QString("%1;%2;%3")
|
|
|
|
.arg(vendorList.indexOf("Mares"))
|
|
|
|
.arg(productList["Mares"].indexOf("Icon HD"))
|
|
|
|
.arg(connectionListModel.indexOf("usb-serial"));
|
|
|
|
} else if (deviceString.contains("mVendorId=4292") && // SiLabs: 0x10c4 / 0xea60,0xea70,0xea71,0xea80
|
|
|
|
(deviceString.contains("mProductId=60000") ||
|
|
|
|
deviceString.contains("mProductId=60016") ||
|
|
|
|
deviceString.contains("mProductId=60017") ||
|
|
|
|
deviceString.contains("mProductId=60032"))) {
|
|
|
|
name = QString("-1;-1;%1")
|
|
|
|
.arg(connectionListModel.indexOf("usb-serial"));
|
|
|
|
} else if (deviceString.contains("mVendorId=1659") && // Prolific: 0x067b / 0x2303
|
|
|
|
deviceString.contains("mProductId=8963")) {
|
|
|
|
name = QString("-1;-1;%1")
|
|
|
|
.arg(connectionListModel.indexOf("usb-serial"));
|
|
|
|
} else if (deviceString.contains("mVendorId=1208") && // Prolific: 0x04b8 / 0x0521,0x0522
|
|
|
|
(deviceString.contains("mProductId=1313") ||
|
|
|
|
deviceString.contains("mProductId=1314"))) {
|
|
|
|
name = QString("-1;-1;%1")
|
|
|
|
.arg(connectionListModel.indexOf("usb-serial"));
|
|
|
|
} else if (deviceString.contains("mVendorId=6790") && // QINHENG: 0x1a86 / 0x7523
|
|
|
|
deviceString.contains("mProductId=29987")) {
|
|
|
|
name = QString("-1;-1;%1")
|
|
|
|
.arg(connectionListModel.indexOf("usb-serial"));
|
|
|
|
} else if (deviceString.contains("mVendorId=3368") && // ARM mBed: 0x0d28 / 0x0204
|
|
|
|
deviceString.contains("mProductId=516")) {
|
|
|
|
name = QString("-1;-1;%1")
|
|
|
|
.arg(connectionListModel.indexOf("usb-serial"));
|
2018-08-09 03:34:39 +00:00
|
|
|
}
|
2018-08-07 01:29:27 +00:00
|
|
|
// inform the QML UI that it should show the download page
|
2018-08-09 03:34:39 +00:00
|
|
|
m_pluggedInDeviceName = strdup(qPrintable(name));
|
2018-08-07 01:29:27 +00:00
|
|
|
emit pluggedInDeviceNameChanged();
|
|
|
|
}
|
2018-08-09 14:12:32 +00:00
|
|
|
|
2020-02-19 20:39:23 +00:00
|
|
|
void QMLManager::setFilter(const QString filterText, int index)
|
2018-10-20 15:59:35 +00:00
|
|
|
{
|
2020-02-19 20:39:23 +00:00
|
|
|
FilterData::Mode mode;
|
2020-02-19 20:43:37 +00:00
|
|
|
// This is ugly - the indexes of the mode are hardcoded!
|
2020-02-19 20:39:23 +00:00
|
|
|
switch(index) {
|
|
|
|
default:
|
|
|
|
case 0: mode = FilterData::Mode::FULLTEXT; break;
|
|
|
|
case 1: mode = FilterData::Mode::PEOPLE; break;
|
|
|
|
case 2: mode = FilterData::Mode::TAGS; break;
|
|
|
|
}
|
2020-02-19 20:43:37 +00:00
|
|
|
DiveListSortModel::instance()->setFilter(filterText, mode);
|
|
|
|
CollapsedDiveListSortModel::instance()->updateFilterState();
|
2018-10-20 15:59:35 +00:00
|
|
|
}
|
|
|
|
|
2019-02-14 06:48:50 +00:00
|
|
|
void QMLManager::setShowNonDiveComputers(bool show)
|
|
|
|
{
|
|
|
|
m_showNonDiveComputers = show;
|
|
|
|
BTDiscovery::instance()->showNonDiveComputers(show);
|
|
|
|
}
|
|
|
|
|
2018-08-09 14:12:32 +00:00
|
|
|
#if defined(Q_OS_ANDROID)
|
|
|
|
// implemented in core/android.cpp
|
|
|
|
void checkPendingIntents();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void QMLManager::appInitialized()
|
|
|
|
{
|
|
|
|
#if defined(Q_OS_ANDROID)
|
|
|
|
checkPendingIntents();
|
|
|
|
#endif
|
|
|
|
}
|
2019-11-19 18:27:20 +00:00
|
|
|
|
2020-02-15 19:44:14 +00:00
|
|
|
#if !defined(Q_OS_ANDROID)
|
2019-11-19 18:27:20 +00:00
|
|
|
void QMLManager::exportToFile(export_types type, QString dir, bool anonymize)
|
|
|
|
{
|
|
|
|
// dir starts with "file://" e.g. "file:///tmp"
|
|
|
|
// remove prefix and add standard filenamel
|
|
|
|
QString fileName = dir.right(dir.size() - 7) + "/Subsurface_export";
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
2020-01-27 00:51:01 +00:00
|
|
|
case EX_DIVES_XML:
|
|
|
|
save_dives_logic(qPrintable(fileName + ".ssrf"), false, anonymize);
|
|
|
|
break;
|
|
|
|
case EX_DIVE_SITES_XML:
|
|
|
|
{
|
2020-02-06 21:38:29 +00:00
|
|
|
std::vector<const dive_site *> sites = getDiveSitesToExport(false);
|
2019-11-19 18:27:20 +00:00
|
|
|
save_dive_sites_logic(qPrintable(fileName + ".xml"), &sites[0], (int)sites.size(), anonymize);
|
|
|
|
break;
|
2020-01-27 00:51:01 +00:00
|
|
|
}
|
|
|
|
case EX_UDDF:
|
2020-02-06 21:38:29 +00:00
|
|
|
exportUsingStyleSheet(fileName + ".uddf", true, 0, "uddf-export.xslt", anonymize);
|
2020-01-27 00:51:01 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qDebug() << "export to unknown type " << type << " using " << dir << " remove names " << anonymize;
|
|
|
|
break;
|
2019-11-19 18:27:20 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-15 19:44:14 +00:00
|
|
|
#endif
|
2019-11-19 18:27:20 +00:00
|
|
|
|
|
|
|
void QMLManager::exportToWEB(export_types type, QString userId, QString password, bool anonymize)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
2020-01-27 00:51:01 +00:00
|
|
|
case EX_DIVELOGS_DE:
|
|
|
|
uploadDiveLogsDE::instance()->doUpload(false, userId, password);
|
|
|
|
break;
|
|
|
|
case EX_DIVESHARE:
|
|
|
|
uploadDiveShare::instance()->doUpload(false, userId, anonymize);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qDebug() << "upload to unknown type " << type << " using " << userId << "/" << password << " remove names " << anonymize;
|
|
|
|
break;
|
2019-11-19 18:27:20 +00:00
|
|
|
}
|
|
|
|
}
|
2019-12-08 10:52:38 +00:00
|
|
|
|
|
|
|
void QMLManager::uploadFinishSlot(bool success, const QString &text, const QByteArray &html)
|
|
|
|
{
|
|
|
|
emit uploadFinish(success, text);
|
|
|
|
}
|
|
|
|
|
2019-12-29 11:29:05 +00:00
|
|
|
qPrefCloudStorage::cloud_status QMLManager::oldStatus() const
|
|
|
|
{
|
|
|
|
return m_oldStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QMLManager::setOldStatus(const qPrefCloudStorage::cloud_status value)
|
|
|
|
{
|
|
|
|
if (m_oldStatus != value) {
|
|
|
|
m_oldStatus = value;
|
|
|
|
emit oldStatusChanged();
|
|
|
|
}
|
|
|
|
}
|
2020-02-18 01:16:11 +00:00
|
|
|
|
|
|
|
void QMLManager::divesChanged(const QVector<dive *> &dives, DiveField field)
|
|
|
|
{
|
|
|
|
Q_UNUSED(field)
|
|
|
|
for (struct dive *d: dives) {
|
|
|
|
qDebug() << "dive #" << d->number << "changed, cache is" << (dive_cache_is_valid(d) ? "valid" : "invalidated");
|
|
|
|
// a brute force way to deal with that would of course be to call
|
|
|
|
// invalidate_dive_cache(d);
|
|
|
|
}
|
|
|
|
}
|