Changeset b2b51c8 in subsurface


Ignore:
Timestamp:
Jun 17, 2017, 11:22:37 PM (2 months ago)
Author:
Dirk Hohndel <dirk@…>
Branches:
master
Children:
4866dd6
Parents:
2d5f023
Message:

QML UI: redesign the user notification

The old system of cloud access updates with fake percentages just wasn't
helpful. Even worse, it hid a lot important information from the user.
This should be more useful (but it will require that we localize the
messages sent from the git progress notifications and make them more
'user ready').

Signed-off-by: Dirk Hohndel <dirk@…>

Files:
9 edited

Legend:

Unmodified
Added
Removed
  • core/checkcloudconnection.cpp

    rb368ecd rb2b51c8  
    5353                                if (verbose > 1)
    5454                                        qWarning() << "Cloud storage: successfully checked connection to cloud server";
    55                                 git_storage_update_progress(false, "successfully checked cloud connection");
     55                                git_storage_update_progress("successfully checked cloud connection");
    5656                                return true;
    5757                        }
    5858                } else if (seconds < prefs.cloud_timeout) {
    5959                        QString text = QString("waited %1 sec for cloud connetion").arg(seconds);
    60                         git_storage_update_progress(false, qPrintable(text));
     60                        git_storage_update_progress(qPrintable(text));
    6161                } else {
    6262                        disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
     
    6464                }
    6565        }
    66         git_storage_update_progress(false, "cloud connection failed");
     66        git_storage_update_progress("cloud connection failed");
    6767        prefs.git_local_only = true;
    6868        if (verbose)
  • core/git-access.c

    r6399eaf rb2b51c8  
    2626bool is_subsurface_cloud = false;
    2727
    28 int (*update_progress_cb)(bool, const char *) = NULL;
    29 
    30 void set_git_update_cb(int(*cb)(bool, const char *))
     28int (*update_progress_cb)(const char *) = NULL;
     29
     30void set_git_update_cb(int(*cb)(const char *))
    3131{
    3232        update_progress_cb = cb;
     
    3939// they also provide information where in the process we are so we can analyze the log
    4040// to understand which parts of the process take how much time.
    41 int git_storage_update_progress(bool reset, const char *text)
     41int git_storage_update_progress(const char *text)
    4242{
    4343        int ret = 0;
    4444        if (update_progress_cb)
    45                 ret = (*update_progress_cb)(reset, text);
     45                ret = (*update_progress_cb)(text);
    4646        return ret;
    4747}
     
    5353        (void) path;
    5454        (void) payload;
    55         static size_t last_percent = -1;
    56 
    57         if (total_steps && 20 * completed_steps / total_steps > last_percent) {
    58                 (void)git_storage_update_progress(false, "checkout_progress_cb");
    59                 last_percent = 20 * completed_steps / total_steps;
    60         }
     55        char buf[80];
     56        snprintf(buf, sizeof(buf),  translate("gettextFromC", "Checkout from storage (%lu/%lu)"), completed_steps, total_steps);
     57        (void)git_storage_update_progress(buf);
    6158}
    6259
     
    6764{
    6865        (void) payload;
    69         static int last_percent = -1;
    70 
    71         int percent = 0;
    72         if (stats->total_objects)
    73                 percent = 16 * stats->received_objects / stats->total_objects;
    74         if (stats->total_deltas)
    75                 percent += 4 * stats->indexed_deltas / stats->total_deltas;
     66
     67        static int last_done = -1;
     68        char buf[80];
     69        int done = 0;
     70        int total = 0;
     71
     72        if (stats->total_objects) {
     73                total = 60;
     74                done = 60 * stats->received_objects / stats->total_objects;
     75        }
     76        if (stats->total_deltas) {
     77                total += 20;
     78                done += 20 * stats->indexed_deltas / stats->total_deltas;
     79        }
    7680        /* for debugging this is useful
    7781        char buf[100];
    7882        snprintf(buf, 100, "transfer cb rec_obj %d tot_obj %d idx_delta %d total_delta %d local obj %d", stats->received_objects, stats->total_objects, stats->indexed_deltas, stats->total_deltas, stats->local_objects);
    79         return git_storage_update_progress(false, buf);
     83        return git_storage_update_progress(buf);
    8084         */
    81         if (percent > last_percent) {
    82                 last_percent = percent;
    83                 return git_storage_update_progress(false, "transfer cb");
     85        if (done > last_done) {
     86                last_done = done;
     87                snprintf(buf, sizeof(buf), translate("gettextFromC", "Transfer from storage (%d/%d)"), done, total);
     88                return git_storage_update_progress(buf);
    8489        }
    8590        return 0;
     
    9196        (void) bytes;
    9297        (void) payload;
    93         static int last_percent = -1;
    94         int percent = 0;
    95 
    96         if (total != 0)
    97                 percent = 5 * current / total;
    98         if (percent > last_percent) {
    99                 last_percent = percent;
    100                 return git_storage_update_progress(false, "push trasfer cb");
    101         }
    102         return 0;
     98        char buf[80];
     99        snprintf(buf, sizeof(buf), translate("gettextFromC", "Transfer to storage (%d/%d)"), current, total);
     100        return git_storage_update_progress("push trasfer cb");
    103101}
    104102
     
    435433        if (verbose)
    436434                fprintf(stderr, "git storage: try to update\n");
    437         git_storage_update_progress(false, "try to update");
     435        git_storage_update_progress("try to update");
    438436        if (!git_reference_cmp(local, remote))
    439437                return 0;
     
    469467        /* Is the remote strictly newer? Use it */
    470468        if (git_oid_equal(&base, local_id)) {
    471                 git_storage_update_progress(false, "fast forward to remote");
     469                git_storage_update_progress("fast forward to remote");
    472470                return reset_to_remote(repo, local, remote_id);
    473471        }
     
    477475                if (verbose)
    478476                        fprintf(stderr, "local is newer than remote, update remote\n");
    479                 git_storage_update_progress(false, "git_update_remote, local was newer");
     477                git_storage_update_progress("git_update_remote, local was newer");
    480478                return update_remote(repo, origin, local, remote, rt);
    481479        }
     
    495493        }
    496494        /* Ok, let's try to merge these */
    497         git_storage_update_progress(false, "try to merge");
     495        git_storage_update_progress("try to merge");
    498496        ret = try_to_git_merge(repo, &local, remote, &base, local_id, remote_id);
    499497        if (ret == 0)
     
    517515        if (verbose)
    518516                fprintf(stderr, "git storage: check remote status\n");
    519         git_storage_update_progress(false, "git check remote status");
     517        git_storage_update_progress("git check remote status");
    520518
    521519        if (git_branch_lookup(&local_ref, repo, branch, GIT_BRANCH_LOCAL)) {
     
    538536                        opts.callbacks.credentials = credential_https_cb;
    539537                opts.callbacks.certificate_check = certificate_check_cb;
    540                 git_storage_update_progress(false, "git remote push (no remote existed)");
     538                git_storage_update_progress("git remote push (no remote existed)");
    541539                error = git_remote_push(origin, &refspec, &opts);
    542540        } else {
     
    562560        if (verbose)
    563561                fprintf(stderr, "sync with remote %s[%s]\n", remote, branch);
    564         git_storage_update_progress(false, "sync with remote");
     562        git_storage_update_progress("sync with remote");
    565563        git_repository_config(&conf, repo);
    566564        if (rt == RT_HTTPS && getProxyString(&proxy_string)) {
     
    589587                // this is not an error, just a warning message, so return 0
    590588                report_error("Cannot connect to cloud server, working with local copy");
    591                 git_storage_update_progress(false, "can't reach cloud server, working with local copy");
     589                git_storage_update_progress("can't reach cloud server, working with local copy");
    592590                return 0;
    593591        }
     
    602600                opts.callbacks.credentials = credential_https_cb;
    603601        opts.callbacks.certificate_check = certificate_check_cb;
    604         git_storage_update_progress(false, "git fetch remote");
     602        git_storage_update_progress("git fetch remote");
    605603        error = git_remote_fetch(origin, NULL, &opts, NULL);
    606604        // NOTE! A fetch error is not fatal, we just report it
     
    617615        }
    618616        git_remote_free(origin);
    619         git_storage_update_progress(false, "done with sync with remote");
     617        git_storage_update_progress("done with sync with remote");
    620618        return error;
    621619}
     
    637635                return NULL;
    638636        }
    639         if (!prefs.git_local_only)
     637        if (!prefs.git_local_only) {
     638                git_storage_update_progress("update remote repo");
    640639                sync_with_remote(repo, remote, branch, rt);
    641 
     640        }
    642641        return repo;
    643642}
     
    775774                fprintf(stderr, "git_remote_repo: accessing %s\n", remote);
    776775        }
    777         git_storage_update_progress(false, "start git interaction");
     776        git_storage_update_progress("start git interaction");
    778777        /* Do we already have a local cache? */
    779778        if (!subsurface_stat(localdir, &st)) {
  • core/git-access.h

    r6399eaf rb2b51c8  
    2626extern void clear_git_id(void);
    2727extern void set_git_id(const struct git_oid *);
    28 void set_git_update_cb(int(*)(bool, const char *));
    29 int git_storage_update_progress(bool reset, const char *text);
     28void set_git_update_cb(int(*)(const char *));
     29int git_storage_update_progress(const char *text);
    3030char *get_local_dir(const char *remote, const char *branch);
    3131int git_create_local_repo(const char *filename);
  • core/load-git.c

    rb368ecd rb2b51c8  
    16761676        git_tree *tree;
    16771677
    1678         git_storage_update_progress(false, "do_git_load, find the commit");
     1678        git_storage_update_progress("do_git_load, find the commit");
    16791679        ret = find_commit(repo, branch, &commit);
    16801680        if (ret)
    16811681                return ret;
    1682         git_storage_update_progress(false, "git commit tree");
     1682        git_storage_update_progress("git commit tree");
    16831683        if (git_commit_tree(&tree, commit))
    16841684                return report_error("Could not look up tree of commit in branch '%s'", branch);
    1685         git_storage_update_progress(false, "load dives from tree");
     1685        git_storage_update_progress("load dives from tree");
    16861686        ret = load_dives_from_tree(repo, tree);
    16871687        if (!ret)
    16881688                set_git_id(git_commit_id(commit));
    16891689        git_object_free((git_object *)tree);
    1690         git_storage_update_progress(false, "done do_git_load");
     1690        git_storage_update_progress("done do_git_load");
    16911691        return ret;
    16921692}
  • core/save-git.c

    r6399eaf rb2b51c8  
    937937        dive_trip_t *trip;
    938938
    939         git_storage_update_progress(false, "start create git tree");
     939        git_storage_update_progress("start create git tree");
    940940        save_settings(repo, root);
    941941
     
    946946
    947947        /* save the dives */
    948         git_storage_update_progress(false, "start saving dives");
     948        git_storage_update_progress("start saving dives");
    949949        for_each_dive(i, dive) {
    950950                struct tm tm;
     
    979979                save_one_dive(repo, tree, dive, &tm, cached_ok);
    980980        }
    981         git_storage_update_progress(false, "done creating git tree");
     981        git_storage_update_progress("done creating git tree");
    982982        return 0;
    983983}
     
    12101210
    12111211        if (!create_empty) // so we are actually saving the dives
    1212                 git_storage_update_progress(false, "start git save");
     1212                git_storage_update_progress("start git save");
    12131213
    12141214        /*
  • desktop-widgets/mainwindow.cpp

    r54bb5cc rb2b51c8  
    6767bool progressDialogCanceled = false;
    6868
    69 extern "C" int updateProgress(bool reset, const char *text)
    70 {
    71         static int percent;
    72 
    73         if (reset)
    74                 percent = 0;
     69extern "C" int updateProgress(const char *text)
     70{
     71        static int progress = 0;
    7572        if (verbose)
    76                 qDebug() << "git storage:" << +percent << "% (" << text << ")";
    77         if (progressDialog)
    78                 progressDialog->setValue(percent);
     73                qDebug() << "git storage:" << text;
     74        if (progressDialog) {
     75                progressDialog->setLabelText(text);
     76                progressDialog->setValue(++progress);
     77                if (progress == 100)
     78                        progress = 0; // yes this is silly, but we really don't know how long it will take
     79        }
    7980        qApp->processEvents();
    8081        return progressDialogCanceled;
     
    20162017        progressDialog = new QProgressDialog(tr("Contacting cloud service..."), tr("Cancel"), 0, 100, this);
    20172018        progressDialog->setWindowModality(Qt::WindowModal);
    2018         progressDialog->setMinimumDuration(200);
     2019        progressDialog->setMinimumDuration(0);
    20192020        progressDialogCanceled = false;
    20202021        connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelCloudStorageOperation()));
  • mobile-widgets/qml/main.qml

    r77a3e6a rb2b51c8  
    2020        property bool fullscreen: true
    2121        property alias oldStatus: manager.oldStatus
    22         property alias accessingCloud: manager.accessingCloud
     22        property alias notificationText: manager.notificationText
    2323        property QtObject notification: null
    2424        property bool showingDiveList: false
     
    2626        property alias showPin: manager.showPin
    2727
    28         onAccessingCloudChanged: {
    29                 // >= 0 for updating cloud, -1 for hide, < -1 for local storage
    30                 if (accessingCloud >= 0) {
    31                         // we now keep updating this to show progress, so timing out after 30 seconds is more useful
    32                         // but should still be very conservative
    33                         showPassiveNotification("Accessing Subsurface cloud storage " + accessingCloud +"%", 30000);
    34                 } else if (accessingCloud < -1) {
    35                         // local storage should be much faster, so timeout of 5 seconds
    36                         // the offset of 2 is so that things start 0 again
    37                         showPassiveNotification("Accessing local storage " + -(accessingCloud + 2) +"%", 5000);
     28        onNotificationTextChanged: {
     29                if (notificationText != "") {
     30                        // there's a risk that we have a >5 second gap in update events;
     31                        // still, keep the timeout at 5s to avoid odd unchanging notifications
     32                        showPassiveNotification(notificationText, 5000)
    3833                } else {
     34                        // hiding the notification right away may be a mistake as it hides the last warning / error
    3935                        hidePassiveNotification();
    4036                }
  • mobile-widgets/qmlmanager.cpp

    rc7a35098 rb2b51c8  
    4141}
    4242
    43 extern "C" int gitProgressCB(bool reset, const char *text)
     43// show the git progress in the passive notification area
     44extern "C" int gitProgressCB(const char *text)
    4445{
    4546        static QElapsedTimer timer;
    4647        static qint64 lastTime;
    47         static QString lastText;
    4848        static QMLManager *self;
    49         static int lastPercent;
    5049
    5150        if (!self)
    5251                self = QMLManager::instance();
    5352
    54         if (!timer.isValid() || reset) {
     53        if (!timer.isValid()) {
    5554                timer.restart();
    5655                lastTime = 0;
    57                 lastPercent = prefs.git_local_only ? -2 : 0;
    58                 lastText.clear();
    5956        }
    6057        if (self) {
    6158                qint64 elapsed = timer.elapsed();
    62                 // don't show the same status twice in 200ms
    63                 if (lastText == text && elapsed - lastTime < 200)
    64                         return 0;
    65                 if (lastPercent < 0)
    66                         lastPercent--;
    67                 else
    68                         lastPercent++;
    69                 self->loadDiveProgress(lastPercent);
    70                 QString logText = QString::number(elapsed / 1000.0, 'f', 1) + " / " + QString::number((elapsed - lastTime) / 1000.0, 'f', 3) +
    71                                   QString(" : git %1 (%2)").arg(lastPercent).arg(text);
    72                 self->appendTextToLog(logText);
    73                 qDebug() << logText;
     59                self->appendTextToLog(text);
     60                self->setNotificationText(text);
    7461                if (elapsed - lastTime > 500)
    7562                        qApp->processEvents();
     
    10289        qDebug() << QStringLiteral("build with Qt Version %1, runtime from Qt Version %2").arg(QT_VERSION_STR).arg(qVersion());
    10390        setStartPageText(tr("Starting..."));
    104         setAccessingCloud(-1);
    10591        setShowPin(false);
    10692        // create location manager service
     
    146132{
    147133        clear_dive_file_data();
     134        setNotificationText(tr("Open local dive data file"));
    148135        QByteArray fileNamePrt = QFile::encodeName(url);
    149136        bool glo = prefs.git_local_only;
    150137        prefs.git_local_only = true;
    151138        int error = parse_file(fileNamePrt.data());
    152         setAccessingCloud(-1);
    153139        prefs.git_local_only = glo;
    154140        if (error) {
    155141                appendTextToLog(QStringLiteral("loading dives from cache failed %1").arg(error));
     142                setNotificationText(tr("Opening local data file failed"));
    156143        } else {
    157144                // if we can load from the cache, we know that we have at least a valid email
     
    173160                DiveListModel::instance()->addAllDives();
    174161                appendTextToLog(QStringLiteral("%1 dives loaded from cache").arg(dive_table.nr));
     162                setNotificationText(tr("%1 dives loaded from local dive data file").arg(dive_table.nr));
    175163        }
    176164        if (oldStatus() == NOCLOUD) {
     
    218206                        // we got an error loading the local file
    219207                        appendTextToLog(QString("got error %2 when parsing file %1").arg(existing_filename, get_error_string()));
     208                        setNotificationText(tr("Error parsing local storage, giving up"));
    220209                        set_filename(NULL, "");
    221210                } else {
    222211                        // successfully opened the local file, now add thigs to the dive list
    223212                        consumeFinishedLoad(0);
    224                         setAccessingCloud(-1);
    225213                        appendTextToLog(QString("working in no-cloud mode, finished loading %1 dives from %2").arg(dive_table.nr).arg(existing_filename));
    226214                }
     
    316304        if (!same_string(prefs.cloud_storage_email, "") &&
    317305            !same_string(prefs.cloud_storage_password, "")) {
    318                 setAccessingCloud(0);
    319306                setStartPageText(tr("Testing cloud credentials"));
    320307                appendTextToLog("Have credentials, let's see if they are valid");
     
    391378        reply->abort();
    392379        reply->deleteLater();
    393         setAccessingCloud(-1);
     380        setNotificationText(QStringLiteral(""));
    394381}
    395382
     
    401388        reply->abort();
    402389        reply->deleteLater();
    403         setAccessingCloud(-1);
     390        setNotificationText(QStringLiteral(""));
    404391}
    405392
     
    435422        setCredentialStatus(VALID);
    436423        setStartPageText("Cloud credentials valid, loading dives...");
    437         git_storage_update_progress(true, "load dives with valid credentials");
     424        git_storage_update_progress("load dives with valid credentials");
    438425        // this only gets called with "alreadySaving" already locked
    439426        loadDivesWithValidCredentials();
    440 }
    441 
    442 void QMLManager::loadDiveProgress(int percent)
    443 {
    444         setAccessingCloud(percent);
    445427}
    446428
     
    475457                error = parse_file(fileNamePrt.data());
    476458        }
    477         setAccessingCloud(-1);
    478459        if (!error) {
    479460                report_error("filename is now %s", fileNamePrt.data());
    480                 const char *error_string = get_error_string();
    481                 appendTextToLog(error_string);
     461                QString errorString(get_error_string());
     462                appendTextToLog(errorString);
    482463                set_filename(fileNamePrt.data(), true);
    483464        } else {
     
    485466                QString errorString(get_error_string());
    486467                appendTextToLog(errorString);
     468                setNotificationText(errorString);
    487469                revertToNoCloudIfNeeded();
    488470                return;
     
    496478        // for the remote data - which then later gets merged with the remote data if necessary
    497479        if (oldStatus() == NOCLOUD) {
    498                 git_storage_update_progress(false, "import dives from nocloud local storage");
     480                git_storage_update_progress("import dives from nocloud local storage");
    499481                dive_table.preexisting = dive_table.nr;
    500482                mergeLocalRepo();
     
    508490                }
    509491        }
    510         setAccessingCloud(-1);
    511492        // if we got here just for an initial connection to the cloud, reset to offline
    512493        if (currentGitLocalOnly) {
     
    544525                setStartPageText(RED_FONT + tr("Failed to connect to cloud server, reverting to no cloud status") + END_FONT);
    545526        }
    546         setAccessingCloud(-1);
    547527        alreadySaving = false;
    548528}
     
    965945{
    966946        if (unsaved_changes()) {
    967                 git_storage_update_progress(true, "saving dives locally"); // reset the timers
     947                git_storage_update_progress("saving dives locally");
    968948                if (credentialStatus() == NOCLOUD) {
    969949                        if (same_string(existing_filename, "")) {
     
    991971                prefs.git_local_only = true;
    992972                if (save_dives(existing_filename)) {
    993                         appendTextToLog(get_error_string());
     973                        QString errorString(get_error_string());
     974                        appendTextToLog(errorString);
     975                        setNotificationText(errorString);
    994976                        set_filename(NULL, true);
    995                         setAccessingCloud(-1);
    996977                        prefs.git_local_only = glo;
    997978                        alreadySaving = false;
     
    1000981                prefs.git_local_only = glo;
    1001982                mark_divelist_changed(false);
    1002                 git_storage_update_progress(false, "done with local save");
     983                git_storage_update_progress("done with local save");
    1003984                alreadySaving = false;
    1004985        } else {
     
    1018999        }
    10191000        // first we need to store any unsaved changes to the local repo
     1001        gitProgressCB("Save changes to local cache");
    10201002        saveChangesLocal();
    10211003
     
    10301012
    10311013        bool glo = prefs.git_local_only;
    1032         git_storage_update_progress(false, "start save change to cloud");
     1014        git_storage_update_progress("start save change to cloud");
    10331015        prefs.git_local_only = false;
    10341016        alreadySaving = true;
    10351017        loadDivesWithValidCredentials();
    10361018        alreadySaving = false;
    1037         git_storage_update_progress(false, "finished syncing dive list to cloud server");
    1038         setAccessingCloud(-1);
     1019        git_storage_update_progress("finished syncing dive list to cloud server");
    10391020        prefs.git_local_only = glo;
    10401021}
     
    13671348}
    13681349
    1369 int QMLManager::accessingCloud() const
    1370 {
    1371         return m_accessingCloud;
    1372 }
    1373 
    1374 void QMLManager::setAccessingCloud(int status)
    1375 {
    1376         m_accessingCloud = status;
    1377         emit accessingCloudChanged();
     1350QString QMLManager::notificationText() const
     1351{
     1352        return m_notificationText;
     1353}
     1354
     1355void QMLManager::setNotificationText(QString text)
     1356{
     1357        m_notificationText = text;
     1358        emit notificationTextChanged();
    13781359}
    13791360
  • mobile-widgets/qmlmanager.h

    r5c1d67e rb2b51c8  
    3030        Q_PROPERTY(credentialStatus_t credentialStatus READ credentialStatus WRITE setCredentialStatus NOTIFY credentialStatusChanged)
    3131        Q_PROPERTY(credentialStatus_t oldStatus READ oldStatus WRITE setOldStatus NOTIFY oldStatusChanged)
    32         Q_PROPERTY(int accessingCloud READ accessingCloud WRITE setAccessingCloud NOTIFY accessingCloudChanged)
     32        Q_PROPERTY(QString notificationText READ notificationText WRITE setNotificationText NOTIFY notificationTextChanged)
    3333        Q_PROPERTY(bool syncToCloud READ syncToCloud WRITE setSyncToCloud NOTIFY syncToCloudChanged)
    3434        Q_PROPERTY(int updateSelectedDive READ updateSelectedDive WRITE setUpdateSelectedDive NOTIFY updateSelectedDiveChanged)
     
    9595        void setLogText(const QString &logText);
    9696
    97         int accessingCloud() const;
    98         void setAccessingCloud(int status);
     97        QString notificationText() const;
     98        void setNotificationText(QString text);
    9999
    100100        bool syncToCloud() const;
     
    127127        void retrieveUserid();
    128128        void loadDivesWithValidCredentials();
    129         void loadDiveProgress(int percent);
    130129        void provideAuth(QNetworkReply *reply, QAuthenticator *auth);
    131130        void commitChanges(QString diveId, QString date, QString location, QString gps,
     
    183182        struct dive *deletedDive;
    184183        struct dive_trip *deletedTrip;
    185         int m_accessingCloud;
     184        QString m_notificationText;
    186185        bool m_syncToCloud;
    187186        int m_updateSelectedDive;
     
    214213        void credentialStatusChanged();
    215214        void oldStatusChanged();
    216         void accessingCloudChanged();
     215        void notificationTextChanged();
    217216        void syncToCloudChanged();
    218217        void updateSelectedDiveChanged();
Note: See TracChangeset for help on using the changeset viewer.