summaryrefslogtreecommitdiffstats
path: root/qt-mobile
diff options
context:
space:
mode:
authorGravatar Dirk Hohndel <dirk@hohndel.org>2016-04-03 19:37:17 -0500
committerGravatar Dirk Hohndel <dirk@hohndel.org>2016-04-04 14:18:22 -0700
commit4af9ee5deaa087bdbbb3ca9a79ff199cc6b89529 (patch)
treeb96ad90772ee4d5dedf7b5197a0c13abec665440 /qt-mobile
parent5821c56da24d0aa02e5bb6d54f14e7651d23269b (diff)
downloadsubsurface-4af9ee5deaa087bdbbb3ca9a79ff199cc6b89529.tar.gz
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>
Diffstat (limited to 'qt-mobile')
-rw-r--r--qt-mobile/qmlmanager.cpp72
-rw-r--r--qt-mobile/qmlmanager.h4
2 files changed, 53 insertions, 23 deletions
diff --git a/qt-mobile/qmlmanager.cpp b/qt-mobile/qmlmanager.cpp
index d6bdaa5cb..3f4e4c2ec 100644
--- a/qt-mobile/qmlmanager.cpp
+++ b/qt-mobile/qmlmanager.cpp
@@ -61,9 +61,11 @@ QMLManager::QMLManager() : m_locationServiceEnabled(false),
deletedDive(0),
deletedTrip(0),
m_credentialStatus(UNKNOWN),
- m_lastDevicePixelRatio(1.0)
+ m_lastDevicePixelRatio(1.0),
+ alreadySaving(false)
{
m_instance = this;
+ connect(qobject_cast<QApplication *>(QApplication::instance()), &QApplication::applicationStateChanged, this, &QMLManager::applicationStateChanged);
appendTextToLog(getUserAgent());
appendTextToLog(QStringLiteral("build with Qt Version %1, runtime from Qt Version %2").arg(QT_VERSION_STR).arg(qVersion()));
qDebug() << "Starting" << getUserAgent();
@@ -78,6 +80,42 @@ QMLManager::QMLManager() : m_locationServiceEnabled(false),
syncLoadFromCloud();
}
+void QMLManager::applicationStateChanged(Qt::ApplicationState state)
+{
+ if (!timer.isValid())
+ timer.start();
+ 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);
+ }
+ stateText.prepend(QString::number(timer.elapsed() / 1000.0,'f', 3) + ": AppState changed to ");
+ stateText.append(" with ");
+ stateText.append((alreadySaving ? QLatin1Literal("") : QLatin1Literal("no ")) + QLatin1Literal("save ongoing"));
+ appendTextToLog(stateText);
+ qDebug() << 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
+ alreadySaving = true;
+ bool cbs = prefs.cloud_background_sync;
+ bool glo = prefs.git_local_only;
+ prefs.cloud_background_sync = true;
+ prefs.git_local_only = false;
+ saveChanges();
+ prefs.cloud_background_sync = cbs;
+ prefs.git_local_only = glo;
+ alreadySaving = false;
+ appendTextToLog(QString::number(timer.elapsed() / 1000.0,'f', 3) + ": done saving to git local / remote");
+ mark_divelist_changed(false);
+ }
+}
+
void QMLManager::openLocalThenRemote(QString url)
{
clear_dive_file_data();
@@ -682,18 +720,11 @@ parsed:
}
DiveListModel::instance()->updateDive(oldModelIdx, d);
}
- if (diveChanged || needResort) {
+ if (diveChanged || needResort)
+ // we no longer save right away, but only the next time the app is not
+ // in the foreground (or when explicitly requested)
mark_divelist_changed(true);
- // this is called "commit" for a reason - when the user saves an
- // edit they have a reasonable expectation that their data is actually
- // stored - so we need to store this to the local cache
- qDebug() << "save dives to local cache";
- prefs.cloud_background_sync = false;
- prefs.git_local_only = true;
- saveChanges();
- prefs.cloud_background_sync = true;
- prefs.git_local_only = false;
- }
+
}
void QMLManager::saveChanges()
@@ -743,11 +774,9 @@ void QMLManager::undoDelete(int id)
}
record_dive(deletedDive);
DiveListModel::instance()->addDive(deletedDive);
- prefs.cloud_background_sync = false;
- prefs.git_local_only = true;
- saveChanges();
- prefs.cloud_background_sync = true;
- prefs.git_local_only = false;
+ // make sure the changes get saved if the app is no longer in the foreground
+ // or if the user requests a save
+ mark_divelist_changed(true);
deletedDive = NULL;
deletedTrip = NULL;
}
@@ -774,7 +803,6 @@ void QMLManager::deleteDive(int id)
}
// if this is the last dive in that trip, remember the trip as well
if (d->divetrip && d->divetrip->nrdives == 1) {
- deletedTrip = (struct dive_trip *)calloc(1, sizeof(struct dive_trip));
*deletedTrip = *d->divetrip;
deletedTrip->location = copy_string(d->divetrip->location);
deletedTrip->notes = copy_string(d->divetrip->notes);
@@ -783,11 +811,9 @@ void QMLManager::deleteDive(int id)
}
DiveListModel::instance()->removeDiveById(id);
delete_single_dive(get_idx_by_uniq_id(id));
- prefs.cloud_background_sync = false;
- prefs.git_local_only = true;
- saveChanges();
- prefs.cloud_background_sync = true;
- prefs.git_local_only = false;
+ // make sure the changes get saved if the app is no longer in the foreground
+ // or if the user requests a save
+ mark_divelist_changed(true);
}
QString QMLManager::addDive()
diff --git a/qt-mobile/qmlmanager.h b/qt-mobile/qmlmanager.h
index 1db4a34ec..15954e9ec 100644
--- a/qt-mobile/qmlmanager.h
+++ b/qt-mobile/qmlmanager.h
@@ -5,6 +5,7 @@
#include <QString>
#include <QNetworkAccessManager>
#include <QScreen>
+#include <QElapsedTimer>
#include "gpslocation.h"
@@ -74,6 +75,7 @@ public:
typedef void (QMLManager::*execute_function_type)();
public slots:
+ void applicationStateChanged(Qt::ApplicationState state);
void savePreferences();
void saveCloudCredentials();
void checkCredentialsAndExecute(execute_function_type execute);
@@ -134,6 +136,8 @@ private:
int m_accessingCloud;
credentialStatus_t m_credentialStatus;
qreal m_lastDevicePixelRatio;
+ QElapsedTimer timer;
+ bool alreadySaving;
signals:
void cloudUserNameChanged();