Разработка для Sailfish OS: таймеры и реализация экспорта в файл на примере примере приложения для ведения списка дел

    Мы уже писали про опыт разработки нашего первого приложения для мобильной платформы Sailfish OS. Но на этом решили не останавливаться и сразу взялись за второе. Целью было создать приложение, с помощью которого пользователь мог бы вести учёт своего рабочего времени, планировать задачи и предоставлять информацию о проделанной работе, иными словами – разработать персональный мобильный тайм-трекер.

    Описание приложения


    Приложение, естественно, должно уметь вести журнал задач с возможность сохранения времени, потраченного на них. Желательно было, чтобы время можно было засекать с помощью встроенного таймера, а не только прописывать руками. Кроме этого, планировалась возможность создание текстовых отчетов о проделанной работе, в виде таблиц, с последующей отправкой их работодателю.

    Так как разработка самой структуры приложения и его интерфейса уже была описана в предыдущих статьях цикла разработки для Sailfish OS (путь от начала разработки до создания первого приложения вы можете отследить здесь и тут), то в этой статье будет описан только функционал, который отличается от реализованного ранее и наиболее интересен с точки зрения его реализации. В нашем приложении — это таймеры задач и экспорт списка задач.

    Таймер


    Для измерения длительности работ в приложении используется механизм таймера. Процесс отсчета времени осуществляется с помощью стандартного элемента Qt Timer, у которого выставлен интервал обновления 1000 миллисекунд.

    Timer {
      id: stopwatch
      interval: 1000
      repeat: true
      running: true
      triggeredOnStart: true
      onTriggered: {
        if (timerActive) {
          var currentTime = new Date ();
          var differeceInTime = (currentTime.getTime() - previousTime.getTime());
          previousTime = currentTime;
          updateData(differentInTime);
        }
      }
    }
    
    function updateData(usec) {
      elapsedTime += usec;
      taskTimerString = getTimeString(elapsedTime);
    }
    

    При каждом срабатывании события onTriggered у Timer происходит вычисление времени таймера: из текущего времени вычитается время предыдущего срабатывания. Такая реализация удобна тем, что при выходе устройства из неактивного режима, время корректно будет обновлятся.

    Для управления таймером сделаны кнопки Старт и Сбросить. Так же есть возможность поставить активный таймер на паузу. Чтобы сохранить замеренное время достаточно нажать на кнопку Сохранить время, доступную в выпадающем меню. Замер таймера автоматически добавится к текущему времени, потраченному на задачу.



    Если пользователь пытается запустить новый таймер, пока активен старый, то будет выведен диалог с возможностью выбрать, как поступить со старым таймером: сбросить данные старого таймера и начать новый, сохранить данные старого таймера и начать новый, перейти к старому таймеру.



    Также, если таймер активен, то он отображается на обложке приложения.

    Экспорт отчетов




    В приложении также реализована функция создания отчетов. Отчет представляет из себя таблицу, содержащую информацию о всех хранящихся в приложении задачах. В таблицу записываются даты начала и окончания задачи, ее название и описание, статус задачи, а также время, потраченное на нее. Список задач берется напрямую из базы данных, при этом задачи выбираются из промежутка, который пользователь сам указывает на экране создания отчетов.

    function selectByPeriod(beginning, end) {
      var database = getDatabase();
      queryResult.clear();
      database.transaction(function(transaction) {
        var tasks = transaction.executeSql('SELECT * FROM tasks WHERE startDate >= ? AND finishDate <= ?',  [beginning, end]);
        for (var i = 0; i < tasks.rows.length; i++) {
          var element = tasks.rows.item(i);
          var startDate = new Date (element.startDate);
          var finishDate = new Date (element.finishDate);
          convertDateToUTC(startDate);
          convertDateToUTC(finishDate);
          var idDone = element.taskDone === 0 ? false : true
          queryResult.append({"startDate": startDate, "finishDate": finishDate, "taskName": element.taskName, "taskDescription": element.taskDescription, "taskDone": isDone, "spentTime": element.spentTime});
        }
      })
    } 
    

    Есть возможность записывать отчеты в файлы двух типов: csv и html. Выбор формата исходного файла происходит также на экране создания отчетов. Для каждого из типов реализован c++ класс, отвечающий за создание соответствующего файла. Запись в csv файлы осуществляется с помощью текстового потока QTextStream. Для корректного отображения кириллицы используется кодировка Windows-1251.

    Q_INVOKABLE void writeLine(QVariantList taskInfo) {
        QTextCodec *utf8 = QTextCodec::codecForName("Windows-1251");
        QTextStream stream(&csvFile);
        QStringList line;
        stream.setCodec(utf8);
        for(int i = 0; i < taskInfo.size(); i++) {
            line << taskInfo[i].toString();
        }
        stream << line.join(",") << endl;
    }
    

    HTML отчеты создаются с помощью класса QTextDocument. Для создания таблицы с информацией по задачам используется класс QTextTable. Он позволяет задать стиль таблицы и текста в ней.

    Q_INVOKABLE void createDocument(int rows, QVariantList columns) {
        report = new QTextDocument();
        QTextCursor cursor(report);
        table = cursor.insertTable(rows + 1, columns.length());
        QTextCharFormat format;
        format.setFontWeight(QFont::Bold);
        QTextCharFormat cellFormat;
        cellFormat.setBackground(QBrush(Qt::cyan));
        for(int col = 0; col < table->columns(); col++) {
            QTextTableCell cell = table->cellAt(0, col);
            QTextCursor cellCursor = cell.firstCursorPosition();
            cell.setFormat(cellFormat);
            cellCursor.mergeCharFormat(format);
            cellCursor.insertText(columns[col].toString());
        }
        QTextTableFormat tableFormat = cursor.currentTable()->format();
        tableFormat.setCellSpacing(0);
        table->setFormat(tableFormat);
    }
    
    Q_INVOKABLE void addRow(int row, QVariantList taskInfo) {
        QTextCharFormat cellFormat;
        cellFormat.setBackground(QBrush(Qt::darkCyan));
        for(int col = 0; col < table->columns(); col++) {
            QTextTableCell cell = table->cellAt(row, col);
            QTextCursor cellCursor = cell.firstCursorPosition();
            cellCursor.insertText(taskInfo[col].toString());
        }
        QTextTableCell indexCell = table->cellAt(row, 0);
        indexCell.setFormat(cellFormat);
    }
    

    Заключение


    В результате было создано приложение с понятным и простым интерфейсом, которое позволяет легко вести и отслеживать список дел. Из ранее не планируемого функционала была добавлена возможность фильтровать задачи по статусу выполнения, чтобы можно было отсеивать выполненные. Приложение было опубликовано в магазине приложений Jolla Harbour под названием Report Card и доступно для скачивания всем желающим. Исходники приложения доступны на GitHub.

    Автор: Максим Костерин
    Метки:
    Поделиться публикацией
    Комментарии 0

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.