Прежде всего хотел бы сказать, что для меня эта история с Sailfish OS началась 1 апреля 2016 года. Не шучу, именно в этот день я получил свой долгожданный Jolla на руки. И понеслось… Копание в ОС, чтение руководств, публикация пары статей на geektimes и первого собственного приложения в официальном магазине.
Однажды, сидя дома, читая Хабр, увидел пост-аннонс о Летней Школе Sailfish OS и сразу решил, что я должен там быть. Через пару недель я уже стоял в г. Иннополис на их главной улице – Университетской.
Картинки кликабельны.
Что это было за место! Что за сообщество разработчиков! Это было невероятно! Кхм… Ладно, отбросим эмоции, давайте по порядку.
27 июля
Это был день знакомств, день вступительных речей, день размещения…
Поселили участников в комфортабельные комнаты на двоих:
В комнатах было все необходимое для небольших перерывов между «порциями» кодинга: кровати, душ, кондиционер, стол. Единственное, в моей комнате было 4 тумбочки на двоих и ноль(!) стульев, я думаю, что Вы догадались как мы использовали 2 «лишние» тумбочки.
С соседом мне особенно повезло, я жил со всеми уважаемым,
К 15.00 все собрались в аудитории №307, где мы фактически и обитали следующие 48 часов.
Мы слушали вступительные речи, общие слова о Sailfish OS, её перспективах в России, о роли «Открытой Мобильной Платформы». Ректор позвал учиться в Иннополис.
Потом выступали партнеры:
Александр Киселёв — Встраивание решений VipNet в Sailfish OS. Говорят, что очень востребованное решение для корпоративного рынка.
Георгий Мартиросов — Безопасный браузер Спутник. Интересно получилось, делали поиск, а в итоге делают браузер… Что же, лично я буду не против, если на Sailfish OS появится конкурент стандартному браузеру.
Егор Левичев, Александр Сержантов — Active Sync на платформе Sailfish OS. Очень интересные ребята. Насчет качества реализации, слышал от пользователей, что очень стабильно работает, жрет мало батарейку, все интегрировано в систему, нативно и «пользователи Android завидуют».
Пётр Барбаняга — Мобильный платёжный кассовый терминал (Sailfish OS).
Вечером нас повели на экскурсию по городу Иннополис:
28 — 29 июля
С этого дня напряжение начинает нарастать в геометрической прогрессии!
С 09.00 начались лекции, перед нами выступали:
Кирилл Чувилин (представитель «Открытой Мобильной Платформы» по связям с сообществом, основатель MaemoWorld.ru) – Обзор Sailfish OS SDK + Мастер-класс разработки графического интерфейса приложения для Sailfish OS. Он рассказывал про особенности SDK, про то, как делать правильно интерфейсы для Sailfish OS, так как ОС выгодно отличается от других: почти все здесь выполняется свайпами, а не нажатием на экран, что требует некой сноровки от разработчика.
Андрей Васильев (представитель FRUCT) – Мастер-класс по работа с основным API Sailfish OS. Это был интересный доклад о том, как «дергать» GPS, управлять различными датчиками, воспроизводить звуки, фотографировать.
Павел Горянский (представитель «Открытой Мобильной Платформы») – аппаратная адаптация Sailfish OS. Павел рассказывал о том, как «завести» Sailfish OS на не поддерживаемых устройствах, что для этого нужно и т. д.
Андрей Кожевников (aka CodeRus, представитель сообщества) –
Петр Вытовтов (aka Osanwe, разработчик нативного клиента для Vkontakte и анализатора Wi-Fi сетей, представитель сообщества) — мастер-класс по работе с сервисами распознавания речи. Проинформировал как можно использовать Yandex Speechkit на Sailfish OS.
Алексей Андреев (победитель хакатона Sailfish OS в Санкт-Петербурге, участник semiot.ru ) – мастер-класс по работе с IoT-устройствами. Было приятно встретить «родственную душу» — человека, который тоже занимается Semantic Web.
В 19.30 начались презентации идей для хакатона, в конечно итоге жизнеспособными оказались следующие проекты:
FriendlyARM порт — проект по адаптации Sailfish OS на плату для разработчиков;
MyFirstProgram — инструментарий для взаимодействия смартфонов и роботехнических конструкторов, таких как ТРИК и Lego NXT;
Battery Stats — утилита для наблюдения за расходом аккумулятора;
GEO-location share — обмен данными о местоположении между устройствами;
Guitar Tuner — настройщик для гитары;
CryptoFish — шифрование файлов по паролю;
Suburban Trains — расписание электричек, основанное на данных Яндекса;
Погода — информация о погоде с учётом местоположения;
Killer — ролевая игра по мотивам психологической игры «Киллер»;
AppCleaner — удаление ненужных данных и приложений;
WatchFox — шифрование домашнего раздела пользователя;
CryptoContainer — защищённое хранение файлов в контейнере;
Timelapse — приложение для интервальной съемки фото и видео.
Да, нынче модны темы с приставкой «крипто», а если серьезно, многих волновала тема безопасности.
Моя же команда решила делать игру по мотивам ролевой игры Киллер. Определились с особенностями реализации:
— Выбор жертвы происходит на сервере (в команде был один из создателей «Killer» под android, поэтому сервер уже был готов);
— Запросы и авторизация в Vkontakte для получения фотографии и имени жертвы;
— «Убийство» «жертвы» с помощью «выстрела» по Bluetooth;
— с помощью GPS программа указывает жертву на Google Maps;
— демон для отслеживания местоположения игрока.
В общем, планы были большие…
Что у нас получилось или как мы не выиграли хакатон, но приобрели огромный опыт
В своей команде я был ответственен за UI, поэтому часть статьи будет посвящена именно ему. Первом делом набросали примерный образ всех страниц (так в Sailfish OS называется каждое «окно») и способы переходов между ними:
Первое испытание началось со страницы выбора жертвы, для этого лучше всего подходил компонент Dialog, оказывается, что разработчики фреймворка Silica не предполагали, что страница с Dialog будет первой страницей приложения и из-за этого Cancel (свайп слева направо работал и выглядел не совсем корректно). Поэтому пришлось схитрить: первой страницей будет пустая страница, с которой будет быстрый переход на DialogPage (пустая страница прорисовывается очень быстро, поэтому пользователю такая «обман» не будет виден).
Исходный код первой страницы:
?import QtQuick 2.0
import Sailfish.Silica 1.0
import "../js/server_request.js" as ServerRequest
Dialog {
id: dialogFirstPage
property string name: "Вася"
property string surname: "Пупкин"
property string imagePath: "../images/avatarUnknown.png"
property string uniqueKey: "Waiting..."
onAccepted: {
console.log("accepted")
// Открываем новую страницу и передаем несколько переменных
pageStack.push(Qt.resolvedUrl("SecondPage.qml"), { "name": name, "surname": surname, "imagePath": imagePath, "uniqueKey": uniqueKey}, PageStackAction.Animated)
}
onRejected: {
console.log("declined")
// Опять открываем эту же страницу
pageStack.push(Qt.resolvedUrl("FirstPage.qml"), {}, PageStackAction.Immediate)
// Делаем запрос к серверу, чтобы получить новую "жертву"
ServerRequest.server_getNextRandomTargetId("34853940", callback_getNextRandomTargetId)
}
function callback_getNextRandomTargetId(responseText) {
uniqueKey = responseText;
}
Column {
anchors.fill: parent
DialogHeader {
acceptText: "Accept"
cancelText: "Cancel"
}
Text {
id: victimText
width: parent.width
horizontalAlignment: Text.Center
color: Theme.highlightColor
font.bold: true
wrapMode: Text.Wrap
font.pixelSize: Theme.fontSizeExtraLarge
text: "Choose new victim:"
}
Image {
id: avatar
source: imagePath
anchors.horizontalCenter: parent.horizontalCenter
width: 400
height: 400
}
Text {
id: nameText
width: parent.width
horizontalAlignment: Text.Center
color: Theme.highlightColor
font.bold: false
wrapMode: Text.Wrap
font.pixelSize: Theme.fontSizeExtraLarge
text: name
}
Text {
id: surnameText
width: parent.width
horizontalAlignment: Text.Center
color: Theme.highlightColor
font.bold: false
wrapMode: Text.Wrap
font.pixelSize: Theme.fontSizeExtraLarge
text: surname
}
Text {
id: keyText
width: parent.width
horizontalAlignment: Text.Center
color: Theme.highlightColor
font.bold: false
wrapMode: Text.Wrap
font.pixelSize: Theme.fontSizeExtraLarge
text: "Victim code:\n" + uniqueKey
}
}
}
Исходный код «хитрости»:
?import QtQuick 2.0
import Sailfish.Silica 1.0
import "pages"
ApplicationWindow
{
// Если пользователь авторизировался, то загружаем FirstEmptyPage.qml (функция проверки пока не написана, поэтому эта страница будет всегда загружаться):
initialPage: true ? Qt.createComponent(Qt.resolvedUrl("pages/FirstEmptyPage.qml")) : Qt.createComponent(Qt.resolvedUrl("pages/LoginPage.qml"))
cover: Qt.resolvedUrl("cover/CoverPage.qml")
allowedOrientations: Orientation.All
_defaultPageOrientations: Orientation.All
// После того как страница полностью подгрузилась открываем сразу нашу настоящую первую страницу:
Component.onCompleted: {
// immediate -> без анимации
pageStack.push(Qt.resolvedUrl("pages/FirstPage.qml"), {}, PageStackAction.Immediate)
}
}
Дальше все пошло легче, авторизацию в Vkontakte сделал с помощью WebView.
?import QtQuick 2.0
import QtQuick.LocalStorage 2.0
import Sailfish.Silica 1.0
import "../js/auth.js" as AuthJS
import "../js/storage.js" as StorageJS
Dialog {
id: loginPage
function checkUrl(url) {
if (AuthJS.checkUrl(url) !== 1) {
console.log(AuthJS.accessToken)
StorageJS.storeSettingsValue("access_token", AuthJS.accessToken)
StorageJS.storeSettingsValue("user_id", AuthJS.userId)
loginView.stop()
loginPage.close()
}
}
SilicaWebView {
id: loginView
anchors.fill: parent
url: "https://oauth.vk.com/authorize?" +
"client_id=4803503" +
"&scope=messages,video,wall,audio,friends,photos,offline" +
"&redirect_uri=https://oauth.vk.com/blank.html" +
"&display=mobile" +
"&response_type=token"
onUrlChanged: checkUrl(url)
}
}
В реализации WebView очень помог код из клиента для VK – Kat. Спасибо автору за замечательное приложение!
Затем на очереди, была страница «Wanted», по содержанию она во многом похожа на DialogPage, но используется компонент PullDownMenu для открытия карты и PullUpMenu для «убийства». Использование PullDownMenu и PullUpMenu:
?import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
// ...
// PullDownMenu и PushUpMenu можно использовать только в SilicaFlickable, SilicaListView или SilicaGridView
SilicaFlickable {
anchors.fill: parent
PullDownMenu {
// Разукрашиваем меню:
backgroundColor: "green"
highlightColor: backgroundColor
// При свайпе сразу будет выбираться option:
quickSelect: true
MenuItem {
text: "Open map"
onClicked: {
console.log(qsTr("Option <Open map> clicked"))
pageStack.push(Qt.resolvedUrl("MapPage.qml"))
}
}
}
contentHeight: column.height
Column {
// ...
}
PushUpMenu {
backgroundColor: "red"
highlightColor: backgroundColor
quickSelect: true
MenuItem {
text: "Kill!"
onClicked: {
console.log(qsTr("Option <Kill!> clicked"))
pageStack.push(Qt.resolvedUrl("EnterCodePage.qml"), {"uniqueKey": uniqueKey})
}
}
}
}
}
Свайпом снизу вверху попадаем на страницу «убийства», к сожалению, мы не успели разобраться с Bluetooth, поэтому придумали следующее: сервер отправляет уникальный код жертве, а «убийца» должен был прочитать его прямо с экрана «жертвы» и ввести его у себя.
Если код не правильный, то даем попытку ввести его еще раз, иначе поздравляем с «убийством» и делаем переход на страницу выбора жертвы.
Таким образом, к концу хакатона мы не успели сделать:
— Запросы в Vkontakte для получения фотографии и имени жертвы;
— «Убийство» «жертвы» с помощью «выстрела» по Bluetooth;
— демон для отслеживания местоположения игрока.
А также провели не самую лучшую презентацию приложения… Но у нас был UI, которым, по крайней мере, лично я реально гордился (хоть он был и с небольшими багами…). Это был колоссальный шаг вперед для меня. До поездки я мог создавать только 1-2 страничное приложение с очень примитивной логикой, к примеру приложение «Chance.»:
После хакатона я почувствовал в себе силы создавать намного более интересные многостраничные программы.
29 июля. Вечер
После завершения хакатона повезли в боулинг-клуб, где всех нас ждал банкет, общение и награждение. После боулинга мы долго не шли спать, обсуждали итоги хакатона, размышляли о Sailfish OS, говорили по душам.
30 июля
Сразу после завтрака организаторы обсудили с участниками пожелания и идеи для развития Sailfish OS. Потом, на прощание, «вывезли в люди» — организовали экскурсию на остров-город Свияжск. После реально отличной экскурсии пришла пора прощаться – Летняя Школа Sailfish OS подошла к концу.
Заключение
Это увлекательное приключение закончилось, потому было немного грустно, но в то же время сердце теплилось от воспоминаний со сколькими безумно интересными людьми познакомился, сколько эмоций и опыта получил. И как интересен этот мир! Можно не выиграть хакатон, провести презентацию приложения не самым удачным образом, проиграть, но получить взамен колоссальный опыт, опыт намного бОльший, чем при победе!
В общем, я ехал домой с твердой уверенностью, что будет моим большим IT-хобби.
Бонус №1
Пара советов для тех, кто еще не участвовал в хакатонах:
— Продумывайте и делайте презентации своих идей/творений как можно качественнее и выступайте эффектней. От этого действительно(!) зависит многое;
— Четко сформулируйте для себя и аудитории задачу минимум и максимум.
Бонус №2
Видео всех выступлений.
Полезные ссылки
» Ссылка на группу в ВК.
» Чат разработчиков в телеграм.
» Timelapse
» Suburban Trains
P.S. Спасибо моим друзьям за первые отзывы и корректуру данной статьи.
UPD: Хотелось бы добавить, что не следует воспринимать опубликованный в этой статье код строго, он был написан на хакатоне и опубликован с небольшими правками, само приложение будет развиваться, очень медленно, но будет. Так что не ругайте сильно :)
Комментарии (10)
GoAlexander
16.08.2016 12:19Уважаемые хабровчане, подскажите, пожалуйста, как перевернуть картинку на хабре?
TreyLav
17.08.2016 11:22Когда-то я менял менял телефон и смотрел на Jolla, но SailfishOS явно была еще не готова.
Когда я последний раз менял телефон, Jolla отчиталась от сокращении половины сотрудников и я побоялся купить потенциально мёртвый девайс.
Позже, они утверждали что нашли финансирование. А что на данный момент? Есть какие-то показатели, планы по развитию и подтверждение жизнеспособности компании? Как я понимаю, железо сейчас на аутсорсе?kirikch
17.08.2016 11:46Наверное, не очень корректно говорить «на аутсорсе». Jolla лицензирует Sailfish OS для производителей железа.
Например, Intex и Turing Robotic Industries выпустили устройства. Oysters и Mobile Inform Group на подходе.
Сама компания занимается теперь софтом совместно с Открытой Мобильной Платформой.
GoAlexander
17.08.2016 13:29На этот год у них 100% есть деньги. + В Индии Aqua Fish покупают, вроде, неплохо (поправьте, если ошибаюсь). От Turing Robotic Industries и Intex Jolla уже получает деньги. То, что Открытая Мобильная Платформа подключилась — радует, так как развитие будет побыстрей идти, так как наработками они обмениваться будут. А дальше… Посмотрим как будут дела у Oysters и насколько хорошо ОМП себя покажет на B2G и B2B рынках в России :)
Segmentq
Честно? Не впечатлился как-то… Особенно браузером Спутник.
kirikch
VipNet, адаптированный за пару недель, тоже не впечатлил? По-моему, очень хороший пример возможности реализации сложных проектов.
kirikch
Или ActiveSync, который интегрируется в систему и не жрёт батарейку, в отличие от аналога, поставляемого с Android.
Меня вот они впечатлили.
Segmentq
А что мешает сделать тоже самое под Android?
kirikch
Не знаю. Быть может, архитектура ОС.
Но ситуация такая, какая есть.
Segmentq
Вот поэтому и не впечатляет…