Клиент ВсеМое.ру – логин

Скорей, надо скорей писать код! Как театр начинается с вешалки, так и любой клиент ВсёМоё начинается с окошка логина. Надо его нарисовать!

Для начала выдираем скриншотом, прямо из эмулятора, работащий логин.

Screen Shot 2014-03-30 at 14.57.55

В оригинале всё, кроме полей ввода и чекбокса, нарисовано прямо на бэкграунде. С одной стороны, это хорошо и уменьшает объем кода. А с другой стороны, ограничивает нарисованным. А ведь охота нарисовать сразу для всех платформ. Ну или практически для всех …

Разбиваем окошко на следующие элементы: бэкграунд, “банка”, логотип, и два поля ввода. Для десктопа еще должна добавиться кнопка “Войти”, ибо на мобильных её функцию выполняет кнопка на виртуальной клавиатуре. Кнопку “регистрация” … а нехай будет

В общем, как-то так получается в реальности.

Screen Shot 2014-03-30 at 15.52.12

Берем Qt Creator и создаем в нем проект, который использует QtQuick.Controls. Мне он поугрожал, что использовать полученное можно будет только с версией iOS больше 5.1 … но найдите мне такую версию живьем?

Создаем в нем фаил ресурсов и загоняем туда картинки, тупо выдранные из оригинала (красоту будем наводить потом).

Для начала нам надо добиться, что бы один и тот же код выполнялся и под десктопом и под айфончиком.

Для этого надо:

а) загнать qml в ресурсы
б) нафиг сменить процедуру загрузки, иначе будут ошибки про not ready и прочее. Короче QTBUG-29873

main.cpp сейчас у меня выглядит так

Screen Shot 2014-03-30 at 17.24.36

Красивая картинка? Полностью полученное можно посмотреть где положено (то есть в git и нефиг ныть!), а у меня получилось следующее:

Screen Shot 2014-03-30 at 17.21.06

Поверьте, на андроиде примерно тоже самое. Теперь необходимо осуществить … гламуризацию всего этого дела. Например, где кнопочка “регистрация” (и нужна ли она)? И все криво при повороте набок. И пароль набирается видимыми буквами. И нету чекбокса. И вообще, все криво.

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

Для начала убираем всякие Column { и тупо прописываем все подряд. Затем добавляем State почти по инструкции http://doc.qt.digia.com/qtquick-components-symbian-1.1/qt-components-scalability-guidelines-orientation-specific-layouts.html

Так как там немного древнее, я заиспользовал одну StateGroup, без отдельной с when:true


StateGroup {
states: [
State {
when: (main.width / main.height) < 1.00

PropertyChanges {
target: loginEmail; text: "portrait"
}

AnchorChanges { target: logoImage; anchors.top: parent.top }
AnchorChanges { target: loginEmail; anchors.top: logoImage.bottom }
// AnchorChanges { target: userPassword; anchors.top: loginEmail.bottom }
},
State {
when: (main.width / main.height) > 1.00

PropertyChanges {
target: loginEmail; text: "landscape"
}
AnchorChanges { target: loginEmail; anchors.top: logoImage.bottom }
// AnchorChanges { target: userPassword; anchors.left: loginEmail.right }
}
]
}

Для проверки я тупо убрал лишнее и в поле для логина начал выводить, какой же State используется. И потом, с помощью PropertyChanges и AnchorChanges я меняю свойства и привязки элементов. В итоге получается “адаптивный” дизайн.

Вот теперь можно и добавить кнопки про регистрацию и вперде!

Правда, вперде прямо сразу не получится. По двум причинам.

Во-первых, для десктопа и мобильного необходимо разные расположения элементов. На мобильном половину (ну или часть) экрана занимает клавиатура, а на десктопе нет. Виндовсные планшеты пока не рассматриваем, их слишком мало, что бы быть принятыми во внимание. И если использовать одну и ту же схему размещения элементов, то либо на мобильном будет криво, либо на десктопе. Некрасиво.

Во-вторых, это долбанное разнообразие разрешений и форматов экрана. У кого-то 4:3, а у кого-то 16:9. Кому-то хватает 640х480 или даже 320 на 240, а кому-то и 1920 на 1080 не хватает.

Что делать?

После некоторого раздумья я решил, что фиг с этими пропорциями. Пусть будет просто две ориентации экрана: горизонтальная и вертикальная.

Для определения платформы (мобильная или десктопная) проще всего использовать предопределенные константы прямо из Qt. напрямую из QML не получится, слишком кроссплатформенный он получился …

Итак, что имеем?

1. ориентацию экрана легко узнать из самого QML. Просто по соотношению высоты и ширины экрана.
2. Ориентацию элементов управления (для мобильного прижимаем кверху, а для десктопа – центрируем) передаем в QML снаружи. Делать свой QML для каждой платформы – моветон.
3. Для удобства позиционирования волевым решением принимаю, что экран в горизонтальной ориентации в реальности имеет размеры 40х30. Кто-то это называет device independed pixels, кто units, кто еще как. И все координаты будут преобразовываться в реальные пикселы отдельной функцией. Сначала засуну ее в QML, а там посмотрим.

Ну, пункт 1 сделан еще на подготовительном этапе.

Теперь надо передать платформу в QML. Обычно народ сразу хватается за классы, но нам-то по идее хватит что-нибудь типа 0 – по центру, 1 – прижимать все вверх.

Для этого тупо устанавливаем переменную для QML

engine.rootContext()->setContextProperty(“platform”,31);

Теперь везде можно использовать platform. Ну и для порядку неплохо бы обернуть все это в обертку из #define

int platform=0;

#ifdef Q_OS_ANDROID
platform=1;
#endif

#ifdef Q_OS_IOS
platform=1;
#endif

#ifdef Q_OS_WINPHONE
platform=1;
#endif

Потом как-нибудь можно будет сделать более тонкое разделение по платформам.

Что касается пикселов, то это решается еще проще.

Где-нибудь в начале QML, сразу после ApplicationWindow вставляю следующее:

property int guxSize: width/40
property int guySize: height/30

function gux(c)
{
return guxSize*c;
}
function guy(c)
{
return guySize*c;
}

Потом везде, где надо привязаться к координатам, использую gux для х/ширины и guy для y/высоты. Опять же, потом мне ничего не мешает переопределить подсчет этих значений для более тонкого соответствия какому-нибудь хитровыделанному дисплею.

Ну а теперь пора переходить к определению элементов и их размеров. При этом крайне рекомендую внутри элемента описаться на его ширину/высоту, а не на guy/gux. Просто потом будет гораздо легче. И никаких pointSize! Только pixelSize.

Как это выглядит в коде, вы можете увидеть в Stage1. В реальности это выглядит так:

Для “десктопа”

landscape

Для “портретного” режима

portrait

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

И да, можно загрузить полученное в телефончик/планшетик и посмотреть, как оно будет выглядеть там. Ну и похвастаться кому-нибудь из знакомых. Всё-таки у вас в руках по настоящему кросс-платформенное приложение.

Клиент ВсёМое.ру – начало

Давно известна старая фраза “если хочешь, что бы было сделано как надо – сделай это сам”. Правда, мало кто продолжает это фразой “ну или по крайней мере начни”.

Из-за чего все это началось? Давным давно (лет 5 наверное назад, если не больше), я озаботился учетом личных финансов. Ну как-то деньги вроде и были, но почему-то сразу и быстро заканчивались. Я перепробовал кучу всяких разных программ для учета финансов и поначалу остановился на GnuCash. Вроде всем хороша и позволяет делать все, что мне необходимо.

Но через некоторое время она стала меня раздражать. Сделав покупку в магазине, мне необходимо было взять чек с собой, потом не потерять его и затем ввести его в программу. Сначала я делал это каждый вечер, потом стал делать по выходным … а потом забил. Все мое существо протестовало против использования меня в качестве тупого приложения к вобщем-то простой программе. Я стал искать варианты для облегчения своей участи … И не нашел. Нет, в сети есть куча сервисов по учету финансов, но все эти сервисы были или рассчитаны на блондинок, или настолько явно использовали мои данные да еще и за мои деньги, что мне становилось нехорошо.

На тот момент я видел единственный выход – создание своего сервиса, с игрищами и блудницами. Подходящий домен у меня был давно заначен и довольно быстро появился vsemoe.ru. Сервис по учету личных финансов. Поначалу появился клиент под iOS, потом постепенно стал проявляться веб-клиент … и тут ситуация застопорилась. Программисты, которым мы давали писать, постепенно его ушатали до безобразия. С каждой новой версией он жирел и обрастал багами вместо улучшения функционала. В общем, ситуация знакомая практически всем. Ситуация осложняется тем, что Objective-C мне категорически не нравится и я попросту часто не врубаюсь в его логику.

Плюс версия для десктопа тоже постоянно мутировала (у меня в репозитории лежит уже 6й или 7й вариант), но до варианта “мне нравится” так и не дотянула.

Что делать? С одной стороны, по хорошему надо сделать рефакторинг кода и вычистить большую часть наслоений. А с другой стороны, мне очень охота сделать логику одинаковой для всех платформ. Иначе версию для андроида я так никогда и не увижу.

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

Скажу сразу: я далеко не профессиональный программист. Говоря нынешними словами, я скорее DevOps с уклоном в сторону администрирования. И я прекрасно сознаю, что кое-какие вещи можно (или даже полагается) делать по-другому. Если знаете как, то помогайте. В общем, начнем.

Для начала я создал аккаунт на гитхабе (https://github.com/kiltum/VseMoe/), в котором и буду выкладывать свои наработки. Опять же, я нагло буду использовать куски уже опубликованного и работающего приложения под iOS (ВсёМоё). Для разработки будут использоваться последние версии Qt/NDK и прочих вещей. Основная работа будет вестись из-под мака (мне так проще).

Итак, что должно получиться в конце?

Screen Shot 2014-03-30 at 15.34.09

Приложение-клиент, работающее под Windows, Linux, OS X, iOS, Android и MobileWindows. Короче, под всеми распространенными платформами. Веб-клиент пишется отдельно и я в него не полезу по простой причине: я не понимаю людей, которые все тащат в браузер, словно дети.

В общем, вперед!