Введение
Общее описание
Структура приложения
Уроки
Описание библиотеки
Приложения

Дополнительный материал

Кастомный функционал

Пользовательский функционал предназначен для выполнения действий, которые на данный момент не выполняются библиотекой. Способы его реализации и подключения к библиотеке декларативного программирования DePro приведены ниже. Первые пять способов применяются если этот функционал будет использован только в одном приложении. Способы 6 и 7 применяются если пользовательский функционал предполагается использовать т в других приложениях.

1. Создание пользовательского экрана

Экран создается как описано ранее:

    activity(name, CustomActivity.class)
или
    fragment(name, CustomFragment.class)

Естественно имена классов пользователь выбирает любые. Класс customActivity имеет вид:

    public class CustomActivity extends BaseActivity implements ICustom{

        @Override
        public int getLayoutId() {
            return R.layout.activity_custom;
        }

        @Override
        public void initView() {
    // Метод выполняется в конце метода onCreate базовой активности. 
    // Здесь Ваш функционал по инициализации необходимх переменных, объектв и пр. 
    // Вам доступен parentLayout, который можете использовать для findViewById или ButterKnife.
        }

    // Здесь будут методы интерфейса ICustom
    }

Если в активности не будут использованы библиотечные компоненты и навигатор, то implements ICustom не нужен.

Класс customFragment имеет вид:

    public class customFragment extends BaseFragment implements ICustom{

        @Override
        public int getLayoutId() {
            return R.layout.fragment_custom;
        }

        @Override
        public void initView(Bundle savedInstanceState) {
    // savedInstanceState - тот, который передается методу onCreateView базового фрагмента.
    // Метод выполняется в конце метода onCreateView базового фрагмента. 
    // Здесь Ваш функционал по инициализации необходимх переменных, объектв и пр. 
    // Вам доступен parentLayout, который можете использовать для findViewById или ButterKnife.
        }

    // Здесь будут методы интерфейса ICustom
    }

Если во фрагменте не будут использованы библиотечные компоненты и навигатор, то implements ICustom не нужен.

Подробно методы интерфейса описаны в приложении. Всем этим методам передается либо viewId, связанного с компонентом, который вызвал метод, либо сам компонент (в виде параметра baseComponent). При необходимости можно определить компонент, который вызвал метод по viewId: mComponent.getComponent(viewId). Здесь mComponent переменнаяя типа Screen в BaseActivity и BaseFragment в которой находится список всех компонентов экрана.

Пример подключения приведен в уроке 2, а пример использования методы интерфейса ICustom можно смотреть в уроках 3 и 7.

2. Подключение кастомного функционала к экрану

Подключение кастомного функционала к экрану осуществляется как описано ранее:

    activity(name, layoutId, AdditionalWork.class)
или
    fragment(name, layoutId, AdditionalWork.class)

Естественно имена классов пользователь выбирает любые. Класс additionalWork имеет вид:

    public class AdditionalWork extends MoreWork {

// Здесь будут методы класса MoreWork.
    }

Так как класс MoreWork реализует интерфейс ICustom, то его методы полностью совпадают с методами интерфейса ICustom. Дополнительным является только метод public void setParam(IBase iBase, Screen screen) который вызывается при инициализации класса MoreWork. В классе MoreWork доступны переменные:

    public IBase iBase;
    public Screen screen;
    public BaseActivity activity;
    public View parentLayout;

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

Пример использования приведен в уроках 3 и 7.

3. Подключение кастомного функционала к компоненту

Подключение кастомного функционала к компоненту осуществляется следующим образом:

    .component(...).addWork(AdditionalWork.class)

Класс AdditionalWork создается как описано выше. Если для компонента подключается кастомный функционал, то действия кастомного функционала экрана (если он есть) для такого компонента игнорируются.

4. Выполнение кастомного функционала в обработчике

Существует обработчик типа EXEC в котором можно указать кастомный функционал:

    handler(viewId, execMethod)

Параметр execMethod описывается следующим образом:

    ExecMethod execMethod = new ExecMethod() {
        @Override
        public void run(BaseComponent component) {
            // Ваши действия
        }
    };

В методе run можно выполнять любые необходимые действия. Параметр component - компонент в навигаторе которого стоит обработчик типа EXEC. Через него можно получить доступ ко всем переменным как компонента, так и экрана.

5. Выполнение кастомного функционала в модели для сложного формирования данных

Если возникнет необходимость получения данных, которые нельзя получить имеющимися методами в модели (хотя это и маловероятно), то можно использовать метод DATAFIELD. В этом случае модель задается следующим образом:

    model(DATAFIELD, dataFieldGet)

параметр dataFieldGet задается следующим образом:

    DataFieldGet dataFieldGet = new DataFieldGet() {
        @Override
        public Field getField(BaseComponent mComponent) {
            Field ff = new Field();
            // Здесь Ваш код по формированию ff
            return ff;
        }
    };

6. Создание пользовательского компонента

Кастомный компонен в классе MyDeclareScreens задается методом component(). Он аналогичен стандартному с одни отличием. Вместо типа компонента указывается класс кастомного компонента:

    .component(MyComponent.class, model(...), view(...), navigator(...))

Параметры model, view и navigator описываются стандартно.

Написание кастомного компонента также не очень сложное. В простейшем случае он имеет вид:

    public class MyComponent extends BaseComponent {

        @Override
        public void initView() {
            componentTag = "MY_COMPONENT_";
            viewComponent = null;
            if (paramMV.paramView != null || paramMV.paramView.viewId != 0) {
                viewComponent = parentLayout.findViewById(paramMV.paramView.viewId);
            }
            if (viewComponent == null) {
                iBase.log("Не найдена View для MyComponent в " + multiComponent.nameComponent);
                return;
            }
        }

        @Override
        public void changeData(Field field) {
            if (field != null) {
                workWithRecordsAndViews.RecordToView((Record) field.value, viewComponent, this, clickView);
            }
        }
    }

Класс должен наследоваться от BaseComponent, или какого нибудь библиотечного компонента. У него должны быть обязательные методы: initView и changeData. В нашем случае в методе initView мы переменную viewComponent связываем с элементом разметки, указанным в методе view описания. В методе changeData мы связываем данные типа Field с viewComponent. Связывание осуществляется методом RecordToView. Он же привязывет к заданным элементам обработку навигатора. Параметр clickView - это метод BaseComponent в котором осуществляетсмя обработка навигатора.

Пример приведен в уроке 10.

7. Создание пользовательского элемента разметки

Каких нибудь предписаний по написанию кастомных элементов разметки нет за исключением общих рекомендаций:

    - Он наследуется от того класса библиотек андроид который Вы считаете наиболее подходящим для Вашего функционала.
    - Желательно использовать интерфейс IAlias.
    - Если он наследуется от AppCompatTextView, AppCompatEditText, AppCompatImageView и Вас устраивает стандартное связывание с элементами этого типа, то интерфейс IComponent можно не использовать.
    - Если Вам нужны собственные действия по связыванию данных, то нужно использовать интерфейс IComponent. В его методах setData и getData описываете необходимые преобразования данных. Для элементов у которых может изменяться статус в методе setOnChangeStatusListener запоминаете передаваемый statusListener. 
            При изменении статуса вы должны этому листенеру передать новый статус следующим образом: statusListener.changeStatus(this, status); Приэтом:
                status = 1, если данные в Вашем элементе начали изменяться;
                status = 2, если данные в Вашем элементе стали валидными;
                status = 3, если данные в Вашем элементе стали не валидными.
            Статус нужно указывать если Ваш элемент будет участвовать в указателях на проверку валидности или на свойство enable, иначе changeStatus не нужен.
    - Если Ваш элемент будет проверяться на валидность, то нужно использовать интерфейс IValidate.

В качестве примеров можно смотреть библиотечные элементы: ComponEditText, ComponTextView и другие.

Поддержка нескольких языков

Для локализации приложения нужно обеспечить 1) локализацию интерфейса, 2) локализацию контента и 3) возможность изменять локаль.

Для локализации интерфейса нужно, во-первых, в соответствии с документацией на андроид для каждого языка нужно в папке res создать папку values-language. Здесь language - ISO код языка может принимать значения ru, en и тому подобное. В этих папках нужно создать строковый ресурс со стрками на соответствующих языках.

Во-вторых нужно задать в MyParams параметру initialLanguage значение локали которая будет отображаться при старте приложения. Если локаль не указана, то юудет браться та, которая установлена на смартфоне.

Для возможности изменения языка приложения нажно в MyParams установить значение параметру nameLanguageInParam.

Для выбора языка можно использовать различные способы. Наиболее приемлемым является применение компонента типа list. Список языков можно ему установить, например, через модель с методом JSON. При выборе элемента списка автоматически будет изменен параметр локали (nameLanguageInParam) и нужно выполнить обработчик с типом действий SET_LOCALE. В результате этого в приложении установится новая локаль и осуществится перезагрузка (recreate) текущей активити. Если будет использован иной способ смены языка, то необходимо предварительно установить значение параметра локали (обработчик с действием SET_PARAM который устанавливает параметры на основе текущего Record).

Для управления языком контента в MyParams нужно задать параметр nameLanguageInHeader. В этом случае все запросы на сервер в списке заголовков будет заголовок с именем указанным в параметре nameLanguageInHeader и значением текущей локали.

Особенности авторизации

Авторизация может быть как одно- так и двухфакторная. Для заполнения логина (адреса e-mail) и пароля желательно использовать библиотечный элемент ComponEditText и EditTextMask для телефона. Эти элементы имеют атрибуты в которых можно задать необходимую проверку на валидность.

После авторизации (логин или регистрация) с сервера должна прийти запись следующего вида {"token":"xxxxxxxxxx ... xxxxx","profile":{ ... }}/ Названия ключей "token" и "profile" могут быть другими, но нужно согласовать с анлроид программистом.

Поэтому в запросе на отправку данных авторизации на сервер нужно задать навигатор after в котором предусмотреть обработчик setToken() и при необхолимости работать с профилем - setProfile(). В результате будет запомнен токен и его значение будет передаваться в заголовке запроса (Естественно при условии задания в классе MyParams параметру nameTokenInHeader имени заголовка токена).

При выполнении обработчика setProfile() профиль запомнится и на всех активных экранах для компонентов у которых тип в модели равняется PROFILE будут обновлены значения.

Проверка валидности перед отправкой данных на сервер

Для элемента разметки при клике на который мы хотим отправить данные на сервер нужно задать обработчик типа CLICK_SEND. В конце этого обработчика перечисляются id элементов разметки которые должны быть валидными перед отправкой данных. Эти элементы должны использовать интерфейс IValidate (все библиотечные элементы в которых осуществляется ввод данных его имеют). Перед списком валидности задается параметр управления свойством Enabled. Если он = true, то кнопка будет активна только при валидности всех элементов, указанных в списке валидности. Активность кнопки будет усанавливаться динамически по мере изменения данных.

Если этот параметр = false, то кнопка активна все время. Валидность будет проверяться после клика на кнопку. Если все данные валидны, то данные отиправятся на сервер, иначе для всех не валидных элементов будут выведены соответствующие сообщения.



Лучше пакета DePro может быть только искусственный интеллект
Задать вопрос
Отправить вопрос