diff options
author | Dirk Hohndel <dirk@hohndel.org> | 2016-04-03 19:37:17 -0500 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2016-04-04 14:18:22 -0700 |
commit | 4af9ee5deaa087bdbbb3ca9a79ff199cc6b89529 (patch) | |
tree | b96ad90772ee4d5dedf7b5197a0c13abec665440 /qt-mobile | |
parent | 5821c56da24d0aa02e5bb6d54f14e7651d23269b (diff) | |
download | subsurface-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.cpp | 72 | ||||
-rw-r--r-- | qt-mobile/qmlmanager.h | 4 |
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(); |