# Слой представления

В основе слоя представления лежит паттерн `MVP` на базе [Moxy](https://github.com/Arello-Mobile/Moxy).

## MVP

В каждой фиче есть `Presenter`, `View`, `Fragment`, `Dagger` модуль, фасад с юзкейсами (`UseCases`), `TargetScreen`

### Presenter

`Presenter` обращается к `domain` слою за данными и для выполнения действий.

`Presenter` наследуется от [BasePresenter](https://nda.ya.ru/t/pst5ZZ7G3yTwrp).

В нём есть общая логика:
- по отписке от данных при уничтожении презентера
- методы для работы с `RxJava`
- скоуп для работы с корутинами

### Интерфейс View

1. Наследуется от [MvpView](https://nda.ya.ru/t/vdUAIdjt3yTxQK).
2. Описывает интерфейс, через который презентер общается с `view`.
3. Функции интерфейса не должны ничего возвращать.
4. Особое внимание нужно уделять стратегиям выполнения функций.

{% note warning %}

Если не уверен на 100% как работает стратегия сама по себе и в связке с другими, почитай код или [статью](https://habr.com/ru/post/276189/) и перепроверь.

{% endnote %}

### View

Чаще всего это фрагмент.
Но у нас также есть `MVP` айтемы в ресайклере.

`View` должна быть максимально тупой, не принимать никаких решений и только что-то отображать и пробрасывать действия пользователя до презентера.

## Навигация

Идея навигации похожа на [Cicerone](https://habr.com/ru/company/mobileup/blog/314838/), но с отличиями.

### Основныес ущности

1. [Command](https://nda.ya.ru/t/G7kKTqbM3yTyYS)
Говорит что нужно сделать.

2. [Navigator](https://nda.ya.ru/t/CuVleaRW3yTyZF)
Выполняет навигацию.
Имеет доступ к `FragmentManager` или ещё чему-то, что непосредственно выполняет переход.

3. [NavigatorHolder](https://nda.ya.ru/t/ojikbeeB3yTyei)
Хранит навигаторы

4. [Router](https://nda.ya.ru/t/dtcySFcR3yTyfm)
Инжектится в презентеры и другие места. Команда из презентера отправляется в роутер, а он уже обогащает её информацией о текщуем экране и т.п. и пробрасывает на выполнение

5. [TargetScreen](https://nda.ya.ru/t/_PxcFY7C3yTywq)
Говорит о том, какой экран открывать и с какими аргументами. Исправлен косяк `Cicerone`, когда аргументы не параметризованы.

6. [NavigationDispatcher](https://nda.ya.ru/t/QqESUcnI3yTz2m)
Ядро навигации. Хранит команды, навигаторы и выполняет отправку команд на навигаторы

### Точки навигации

1. [Flow](https://nda.ya.ru/t/nGyS7_FM3yTzEj)
Самый крупный компонент.
Нужен для того, чтобы показать пользователю не стандартный экран с табами, а что-то другое (как открыть новую `Activity`, но без `Activity`).
Типичный пример - `Flow.TABS`.

2. [TabsFragment](https://nda.ya.ru/t/hnml-wgl3yTzZU)
Содержит в себе табы и контейнер, в котором отображается контент каждого таба

3. [TabContainerFragment](https://nda.ya.ru/t/S2EakCF63yTzmW)
Содержит в себе контейнер для экранов и `FragmentManager` для навигации между экранами

### Логика

Отправляем команду на открытие экрана

Команда прилетает в `NavigationDispatcher` и пытается выпониться на навигаторах.
- Если навигатор может снавигировать на экран, то он делает это и возвращает `CommandResult.COMPLETELY_EXECUTED`
- если не может ничего сделать, то `CommandResult.NOT_EXECUTED`
- если может поспособствовать, то `CommandResult.PARTIALLY_EXECUTED`

#### Пример 1

Пробуем с морды открыть экран поиска.
1. Команда попадает в первую очередь в `FragmentBackStackNavigator` и он добавляет в стек экранов экран поиска.

#### Пример 2

Пробуем с морды открыть экран моих заказов.
1. Команда попадает в `FragmentBackStackNavigator`, там проверяется, можно ли открыть экран в данном табе.
Экран моих заказов нельзя открыть в табе главной. Поэтому возвращается `CommandResult.NOT_EXECUTED`.
2. Команда уходит дальше в `TabsNavigator`
Он видит, что экран открывается только на экране профиля, значит нужно переключить таб. Делает это. И возвращает `CommandResult.PARTIALLY_EXECUTED`, так как он может только переключить таб, но не открыть экран.
3. Команда попадает в `MainNavigator`. Он видит, что данный экран открывается в `Flow.Tabs` и он сейчас активен. Значит ничего не сделать. Возвращает `CommandResult.NOT_EXECUTED`.
4. Тем временем в новом открытом табе регистрируется новый `FragmentBackStackNavigator`, который соответстует табу профиля. Команда всё в очереди, так как экран моих заказов никто не открыл.
Команда прилетает в только что добавленный навигатор и он может открыть экран моих заказов. Возвращает `CommandResult.COMPLETELY_EXECUTED`.
5. Команда удаляется из очереди

#### Пример 3
Пробуем открыть экран дооплаты с морды.
1. Команда попадает в `FragmentBackStackNavigator`, там проверяется, можно ли открыть экран в данном табе.
Экран дооплаты нельзя открыть ни в одном табе. Поэтому возвращается `CommandResult.NOT_EXECUTED`.
2. Команда уходит дальше в `TabsNavigator`
Экран дооплаты нельзя открыть ни в одном табе. Поэтому возвращается `CommandResult.NOT_EXECUTED`.
3. Команда попадает в `MainNavigator`.
Он видит, что экран дооплаты должен открываться во `Flow.CHANGE_PAYMENT_METHOD`.
Поэтому открывает фрагмент, который является контейнером для данного `FLow`. И Возвращает `CommandResult.PARTIALLY_EXECUTED`, так как он не открыл сам экран, а только поспособствовал этому.
4. Дальше новый контейнер регистрирует свой навигатор.
5. Команда попадает в новый навигатор и он добавляет нужный экран. И возвращает `CommandResult.COMPLETELY_EXECUTED`.

Остальные команды действуют по такой же схеме.

## Форматтер и ViewObject

`Formatter` - это аналог маппера, только для `presentation` слоя.

Не всегда удобно отображать доменную модель, иногда удобнее её смаппить в так называемый `ViewObject` (Vo).
Этим и занимаются форматтеры. Назвали их так, чтобы не путать с мапперами из `data` слоя.

{% note warning %}

Форматтеры не задают ресурс картинки. Они могут только задать тип картинки в виде `enum`.
Это потому, что для разных размеров экранов и т.п. могут требоваться разные картинки. А в форматтерах у нас нет доступа к такой информациии.

{% endnote %}

Также, `Vo` нужен для того, чтобы передавать данные на другие экраны, когда это требуется.
В таком случае они должны наследоваться от `Parcelable`. Но, как мы знаем, в доменных сущностях не должно быть `android` зависимостей.
