В этот раз мы рассмотрим способ создания окна-заставкои (Splash Screen) для WebOS-приложений. Заставка, хотя и не несет функциональной роли в приложении, может быть очень полезна для привлечения пользователей, ведь это именно то, что пользователь видит при запуске вашего приложения. Кроме того, на splash screen’е можно разместить, например, индикатор загрузки или еще какую-нибудь полезную (например с маркетиноговой точки зрения) информацию.Для того, чтобы сделать ЭТО создадим новый проект и в нем две сцены – main и splash.
app/views/main/main-scene.html

<div id="ExitButton" x-mojo-element="Button"></div>

app/assistants/main-assistant.js

function MainAssistant() {
}

MainAssistant.prototype.setup = function() {
    this.controller.setupWidget("ExitButton", {}, {label:"Exit"});
    Mojo.Event.listen($(ExitButton), Mojo.Event.tap, this.onExit.bind(this));
    this.controller.stageController.pushScene("splash");
}

MainAssistant.prototype.onExit = function(event) {
    this.controller.stageController.getAppController().closeAllStages();
    window.close();
}

MainAssistant.prototype.cleanup = function(event) {
    Mojo.Event.stopListening($(ExitButton), Mojo.event.tap, this.onExit);
}

app/assistants/stage-assistant.js

function StageAssistant() {
}

StageAssistant.prototype.setup = function() {
    this.controller.pushScene("main");
}

Stage Assistant просто запускает сцену main.

Главная сцена содержит одну кнопку, нажав которую можно выйти из приложения. При инициализации сцены мы отображаем сцену splash.

Но если мы все оставим как есть, то вместо рабочего приложения получим просто пустую сцену (т.к. сцена splash, которая автоматически становится активной, не содержит никаких виджтов. Будем это исправлять.

Создадим изображение размером 320×480, назовем его splash.jpg и положим его в папку images нашего проекта.

Теперь в CSS-файле проекта пропишем следующее:
stylesheets/splashscreentest.css

body.splash {
    position: absolute;
    top: 0;
    left: 0;
    height: 454px;
    width: 320px;
    background: url(../images/splash.jpg) no-repeat;
    z-index: 100;
}

В этом CSS-файле для класса splash мы указываем фоновое изображение. Для того чтобы это фоновое изображение было отображено на сцене splash, нам надо добавить CSS-класс splash к тегу body сцены.

app/assistants/splash-assistant.js

function SplashAssistant() {
}

SplashAssistant.prototype.setup = function() {
    $$('body')[0].addClassName('splash');
    this.splashTimer = setTimeout(this.removeSplashScreen.bind(this), 4000);
}

SplashAssistant.prototype.removeSplashScreen = function() {
    this.controller.stageController.popScene();
    clearTimeout(this.splashTimer);
}

SplashAssistant.prototype.deactivate = function(event) {
    $$('body')[0].removeClassName('splash');
}

В assistant-классе сцены splash при инициализации мы добавляем класс splash к тегу body, а при деактивации сцены удаляем этот класс из тега body. Также, при инициализации мы запускаем таймер, в обработчике собфтия для этого таймера закрываем сцену.

В результате у нас получается такое:

WebOS Create Splash Screen

Скачать исходный код примера.

Previous ArticleNext Article
Технический директор IT-Dimension, компании-разработчика кросс-платформенного программного обеспечения

Leave a Reply

Your email address will not be published. Required fields are marked *

И.

Использование HTML5 Depot для хранения данных в Palm WebOS

Для начала давайте разберемся, что такое Depot и зачем он может понадобиться в приложениях для Palm WebOS.

Если ваше приложение должно хранить данные, то в таком случае есть три варианта:

  • Использование Cookies
  • Использование базы данных SQLite
  • Использование Depot

Но в каких же случаях есть смысл использовать каждый из перечисленных вариантов? Если необходимо сохранить небольшой объем данных, например настройки приложения, то лучше использовать Cookies. Если же объем данных относительно большой, то выбор должен быть сделан в пользу одного из оставшихся способов. Какой из них лучше?

Что лучше использовать – зависит от объема данных, которые нужно хранить, а также от того, где вы будете хранить эти данные. Если вы используете хранилище по умолчанию (кстати Depot переводится как “хранилище” или “склад”), то у вас объем данных будет ограничен одним мегабайтом.

Если вам необходимо хранить данные в структурированном виде, то лучше сделать выбор в пользу базы данных SQLite.

Кстати, ограничение на 1 МБ данных можно обойти, разместив хранилище на разделе с медиа. В этом случае размер хранилища будет ограничен только объемом свободной памяти на это мразделе.

В чем же отличие Depot от базы данных SQLite? Depot может хранить только объекты. Например сделать так чтобы хранилась только булевая переменная не получится, нужно обязательно сделать объект и эту булевую переменную указать в виде свойства.

{ "value" : true }

Тоесть, что получается: Depot – это неструктурированное хранилище объектов. На самом деле это просто еще один уровень абстракции над API по работе с базами данных SQLite, но он позволяет избавиться от необходимости писать SQL в коде, что довольно удобно.

Перед тем, как рассматривать пример использования Depot, давайте создадим каркас приложения и потом в него уже будем добавлять необходимый функционал:

app/views/main/main-scene.html

<div id="main" class="palm-hasheader">
  <div class="palm-header">Depot Test</div>
  <div id="AddSceneButton" x-mojo-element="Button"></div>
  <div id="info" x-mojo-element="x-body-text"></div>
</div>

app/assistants/main-assistant.js

function MainAssistant() {
}

MainAssistant.prototype.setup = function() {
  this.controller.setupWidget("AddSceneButton", {}, {label:"Add"});
  Mojo.Event.listen(this.controller.get("AddSceneButton"),
    Mojo.Event.tap,
    this.handleAddSceneButton.bind(this));
}

MainAssistant.prototype.handleAddSceneButton = function(event) {
  this.controller.stageController.pushScene("add");
}

app/views/add/add-scene.html

<div id="main" class="palm-hasheader">
  <div class="palm-header left" id="list-header">
    Add / replace data
  </div>
</div>
<div class="palm-group">
  <div class="palm-group-title"><span x-mojo-loc="">Database Info.</span></div>
    <div class="palm-list">
      <div class='palm-row first'>
        <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
          <div class="title">
            <div class="label">Key</div>
            <div id="keyField" name="keyField" x-mojo-element="TextField" ></div>
          </div>
        </div>
      </div>
      <div class='palm-row last'>
        <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
          <div class="title">
            <div class="label">Text</div>
            <div id="textField" name="textField" x-mojo-element="TextField" ></div>
          </div>
        </div>
      </div>
    </div>
</div>
</div>
<div id="depotResult" class="info-text"></div>
<div x-mojo-element="Button" id="add_button"></div>
<div x-mojo-element="Button" id="back_button"></div>

app/assistants/add-assistant.js

function AddAssistant() {
}

AddAssistant.prototype.setup = function() {
  this.controller.setupWidget('keyField',
    {
      hintText:       'Enter key here',
      modelProperty:  'originalValue',
      textCase:       Mojo.Widget.steModeLowerCase,
      focus:          true,
      maxLength:      30
    },
    {
      originalValue : ''
    });
  this.controller.setupWidget('textField',
    {
      hintText:       'and some text here',
      modelProperty:  'originalValue',
      textCase:       Mojo.Widget.steModeLowerCase,
      multiline:      false,
      focus:          false,
      maxLength:      30
    },
    {
      originalValue : ''
    });
  this.controller.setupWidget("add_button", {}, {label:"Add entry"});
  this.controller.setupWidget("back_button", {}, {label:"Back to main view"});

  Mojo.Event.listen(this.controller.get("add_button"),
    Mojo.Event.tap, this.handleAddButton.bind(this));
  Mojo.Event.listen(this.controller.get("back_button"),
    Mojo.Event.tap, this.handleBackButton.bind(this));
}

AddAssistant.prototype.cleanup = function() {
  this.controller.stopListening(
    this.controller.get('add_button'), Mojo.Event.tap,
    this.handleAddButton);
  this.controller.stopListening(
    this.controller.get('back_button'), Mojo.Event.tap,
    this.handleBackButton);
}

AddAssistant.prototype.deactivate = function(event) {
}

AddAssistant.prototype.handleAddButton = function(event) {
}

AddAssistant.prototype.handleBackButton = function(event) {
  this.controller.stageController.popScene();
}

На главной форме у нас находится кнопка Add, которая вызывает сцену, в которой можно добавить новые записи в Depot.
Форма добавления новых записей содержит заголовок, группу из двух текстовых полей и две кнопки – кнопку добавления новой записи и кнопку закрытия сцены.
WebOS Depot Test

Ну вот, GUI готово, теперь можем начинать работу с Depot.

function MainAssistant() {
  var options = {
    name: "depot_tutorial", //Название хранилища (обязательный параметр)
    version: 1, //Версия базы данных. (опционально, по умолчанию 1)
    replace: false // открывать существующее хранилище
  };
  this.depot = new Mojo.Depot(options,
    this.dbConnectionSuccess.bind(this),
    this.dbConnectionFailure.bind(this));
}

MainAssistant.prototype.dbConnectionSuccess = function() {
    this.controller.get("info").update('OK');
}

MainAssistant.prototype.dbConnectionFailure = function() {
    this.controller.get("info").update('Error');
}

При создании объекта Depot можно указать методы, которые будут отрабатывать при успешном подключении к хранилищу или же при ошибке подключения.

Если надо создать хранилище на разделе с медиа, то название хранилища будет выглядеть так:

name: "ext:depot_tutorial"

У нас есть сцена, в которой должно происходить добавление объектов в Depot. Нам надо передать в нее объект Depot в качестве параметра. Сделать это можно вот как:
app/assistants/main-assistant.js

MainAssistant.prototype.handleAddSceneButton = function(event)
{
    this.controller.stageController.pushScene("add", this.depot);
}

app/assistants/add-assistant.js

function AddAssistant(arg) {
    this.depot = arg;
}

Мы передаем объект Depot в качестве параметра pushScene() и этот объект будет получен сценой как параметр конструктора.
Теперь нам необходимо написать обработчик кнопки add_button, в котором значение из текстового поля TEXT будет добавляться в хранилище с ключем KEY.

AddAssistant.prototype.handleAddButton = function(event) {
    this.data = { "value" :this.textModel.originalValue };
    this.depot.simpleAdd(this.keyModel.originalValue,
        this.data, this.dbAddSuccess, this.dbAddFailure);
}

AddAssistant.prototype.dbAddSuccess = function(event) {
    this.depotResult.innerHTML = ("Add success!");
}

AddAssistant.prototype.dbAddFailure = function(event) {
    this.depotResult.innerHTML = ("Add failure!");
}

В обработчике кнопки Add мы создаем объект, в нем в свойстве value запоминаем введенный текст и затем записываем в Depot. Запись происходит путем вызова метода simpleAdd(), в котором мы указываем ключ, сохраняемый объект, а также два callback-метода, которые будут вызваны при удачном или неудачном завершении операции записи.

И вот, мы научились добавлять объекты в Depot. Теперь попробуем научиться их оттуда доставать.

Создадим новую сцену с названием get.

app/views/get/get-scene.html

<div id="main" class="palm-hasheader">
  <div class="palm-header left" id="list-header">
    Retrieve data
  </div>
</div>
<div class="info-text">Which data entry you want to get?</div>

<div class="palm-group">
<div class="palm-group-title">Enter key string</div>
  <div class="palm-list">
    <div class="palm-row single">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div id="entryNum" x-mojo-element="TextField" ></div>
        </div>
      </div>
    </div>
  </div>
</div>
<div id="response" class="info-text"></div>
<div x-mojo-element="Button" id="get_button"></div>
<div x-mojo-element="Button" id="back_button"></div>

app/assistants/get-assistant.js

function GetAssistant(arg) {
    this.depot = arg;
}

GetAssistant.prototype.setup = function() {
    this.controller.setupWidget("get_button", {}, {label:"Get value"});
    this.controller.setupWidget("back_button", {}, {label:"Back to main view"});
    this.controller.setupWidget('entryNum',
        {
            hintText:       'Enter key here',
            modelProperty:  'originalValue',
            textCase:       Mojo.Widget.steModeLowerCase,
            multiline:      false,
            focus:          true,
            maxLength: 30
        },
        this.keyModel =
        {
            originalValue : ''
        });

    Mojo.Event.listen(this.controller.get('get_button'),
        Mojo.Event.tap, this.handleGetButton.bind(this));
    Mojo.Event.listen(this.controller.get("back_button"),
        Mojo.Event.tap, this.handleBackButton.bind(this));
}

GetAssistant.prototype.cleanup = function(event) {
    this.controller.stopListening(
        this.controller.get('get_button'), Mojo.Event.tap,
        this.handleGetButton);
    this.controller.stopListening(
        this.controller.get('back_button'), Mojo.Event.tap,
        this.handleBackButton);
}

GetAssistant.prototype.handleGetButton = function(event) {
    this.depot.get(this.keyModel.originalValue,
        this.dbGetSuccess.bind(this),
        this.dbGetFailure.bind(this));
}

GetAssistant.prototype.dbGetSuccess = function(response) {
    var recordSize = Object.values(response).size();
    if(recordSize == 0) {
        this.controller.get("response").innerHTML = "No such record in the database";
    } else {
        this.controller.get("response").innerHTML = "Data entry is: " + response.value;
    }
}

GetAssistant.prototype.dbGetFailure = function(transaction, result) {
    this.controller.get("response").innerHTML = "Error: " + result.message;
}

GetAssistant.prototype.handleBackButton = function(event) {
    this.controller.stageController.popScene();
}

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

WebOS Depot Search GUI

Для получения объекта из хранилища мы используем метод get() объекта Depot. В этом методе указывается ключ и callback-методы, которые отработают при удачном или неудачном завершении транзакции.

На этом все. В этой статье мыузнали:

  • Чем отличается Depot от базы данных SQLite.
  • Как создать объект Depot в хранилище по умолчанию или на разделе с медиа
  • Как создать соединение с Depot
  • Как записать данные в Depot
  • Как получить данные из Depot
  • Как обрабатывать результаты транзакций в callback-методах.

Скачать исходный код примера.

С.

Симуляция аппаратных событий в эмуляторе Palm WebOS

В эмуляторе WebOS есть возможность программно симулировать аппаратные события, например входящий телефонный звонок, входящее SMS или изменение GPS-координат. Такая возможность может быть полезна, например, при отладке приложений, использующих GPS.

Для симуляции аппаратных событий в Palm Mojo SDK используется утилита luna-send, которая отправляет сообщения сервису pmradiosimulator в эмуляторе. Об использовании утилиты luna-send и пойдет речь в этот раз.

Синтаксис вызова luna-send
luna-send -n 1 URL JSON_object

Параметр URL позволяет указать аппаратное событие, которое должно быть симулировано. Параметр JSON_object позволяет указать параметры вызова сервиса pmradiosimulator.

Примеры использования

Симуляция входящего телефонного звонка:

luna-send -n 1 luna://com.palm.pmradiosimulator/set_incomingcall {\"number\":\"14086177431\"}
Симуляция входящего SMS:
luna-send -n 1 luna://com.palm.pmradiosimulator/set_incomingsms {\"number\":\"4086177431\",\"
message\":\"'Hello World! Incoming SMS.'\"}
Изменение GPS-координат
luna-send -n 1 luna://com.palm.pmradiosimulator/set_position {\"lat\":\"37.3\",\"long\":\"-122\"}
Изменение оператора сотовой связи (применяется после перезагрузки)
luna-send -n 1 luna://com.palm.pmradiosimulator/set_operator {\"operator\":\"Sprint\"}

GPS AutoDrive

Фyкция GPS AutoDrive в эмуляторе позволяет использовать CSV-файл с записанным GPS-треком при запросе координат приложениями, использующими GPS. Таким образом можно симулировать передвижение по заданному маршруту.

Запуск функции AutoDrive
luna-send -n 1 luna://com.palm.pmradiosimulator/autodrive/start {}

Если имя CSV-файла с запиью трека не указано, то будет использоваться файл /var/lib/til/AutoDrive_DefaultRoute.csv.

Остановка режима AutoDrive
luna-send -n 1 luna://com.palm.pmradiosimulator/autodrive/stop {}

После остановки AutoDrive координаты GPS будут установлены в значения по умолчанию (Palm Sunnyvale).

Установить AutoDrive в реверсный режим
luna-send -n 1 luna://com.palm.pmradiosimulator/autodrive/reverse {}
Приостановить AutoDrive
luna-send -n 1 luna://com.palm.pmradiosimulator/autodrive/pause {}
Восстановить режим AutoDrive после паузы
luna-send -n 1 luna://com.palm.pmradiosimulator/autodrive/resume {}
Ускорить режим AutoDrive
luna-send -n 1 luna://com.palm.pmradiosimulator/autodrive/speedup {}
Замедлить режим AutoDrive
luna-send -n 1 luna://com.palm.pmradiosimulator/autodrive/slowdown {}

CSV-файл трека

По умолчанию для задания GPS-трека используется файл AutoDrive_DefaultRoute.csv. Для того, чтобы указать другой файл трека, необходимо вызвать функцию set_route сервиса pmradiosimulator:

luna-send -n 1 luna://com.palm.pmradiosimulator/autodrive/set_route \{\"route\":\"/var/lib/MyGpsRoute.csv\"}

Формат CSV-файла трека описан здесь.