Приложение основано на архитектуре MVC, где небольшие компоненты работают в связи View-Model. Проект использует CocoaPods.
Главная страница - UsersListViewController. Он содержит в себе экземпляр класса UITableView с кастомными ячейками. У каждой ячейки (UserListCell) есть своя модель данных (UserListCellVM). В модели хранится информация о пользователе.
Контроллер отвечает за запрос на получение пользователей (описан ниже, 'NetworkLayer') и прорисовку. Имеется кнопка '+', для перехода на страницу создания пользователя. При тапе на ячейку переходим на ту же страницу, но уже в режиме редактирования.
Представляет из себя контроллер с объектом UIScrollView в корне, в котором хранится объект класса UIStackView, где subViews - обекты TextField (кастомный класс описан ниже, 'View'). Так же имеется объект UIImageView для показа аватара.
Класс обрабатывает closure переменной keyboardHelper (описан ниже, 'Helpers'), для изменения лэйатуов страницы, чтобы клавиатура не покрывала кнопку создать/редактировать и корректно отображалась на девайсах с маленькими экранами.
Содержит переменную inputData типа NewUser (описан ниже, 'Models'), которая используется для передачи данных, когда контроллер открывается для уже существующего пользователя.
Логика страницы изменяется, поля и аватар (при наличии) заполняются, когда inputData заполнен информацией о пользователе.
Существуют computed property для валидации:
- isValid - проводит проверку validationError у объектов класса TextView (кастомный класс описан ниже, 'View')
- hasChanges - сверяет данные из inputData и изменения в полях, чтобы распознать изменения информации о пользователе. Добавлен для того, чтобы избегать лишних запросов.
- isFilled - проверяет с помощью reduce поля на пустоту, так как исходя из бизнес логики недопустимо создание пользователя без информации об имени, фамилии и почты.
Была создана некая прослойка для работы с фреймворком Alamofire под названием RequestService для вызова запросов и получения ответов, которые декодятся в Resource. Запросы конфигурируются с помощью класса UserAction и протоколов APIAction и APIClient.
Были созданы "классы-помощники" EmailValidator и KeybopardHelper. Первый отвечает за валидацию почтового адреса и возвращения результата валидации, а второй - отдельный класс для обработки ивентов клавиатуры, который передает информацию для обработки через closure.
В проекте есть 3 модельки - User, NewUser и CustomError.
User - он конформит протокол Codable и создает модель пользователя, когда Мы получаем о нем ифнормацию после запроса
NewUser - используется при создании/редактировании пользователя. Является укороченным вариантом модельки User для более удобного использования.
CustomError - испольуется для создания ошибки с кастомным текстом.
TextField - это наследник MFTextField (фреймворк MaterialTextField), который представляет из себя поле с анимациями. В нем некие кастомные конфигурации по части UI.
LoadingView - кастомный View, который содержит в себе ActivityIndicator. Используется для показа на экране во время загрузки/отправки данных.
В проекте существует одна кастомная ячейка - UserListCell, которая конформит протокол NibReusable (фреймворк Reusable), который облегчает для нас процесс реюза ячейки. Объект класса UserListCell используется для показа информации о пользователе в объекте класса UITableView на главной странице.
Он имеет в себе доступную извне переменную viewModel типа UserListCellVM, при установке которого в его didSet вызывается функция для конфигурации контента.
В проекте использован популярный фреймворк Kingfisher для работы с картинками. Так же есть расширение UIImageView+, где методы данного фреймвррка обернуты для избежания дубликации кода и читаемости.
Просходит в Main.storyboard, а для ячеек используется XIB-файл.
Используется фреймворк SwiftGen, который с помощью скрипта генерирует файлы Assets и Localizations, для более читаемого доступа к файлами и текстам.
Так как нет предоставленного способа загрузки картинок, логическая часть, связанная с установкой/изменением аватара у пользователя отсутствует, можно только визуально увидеть результат работы с UIImagePickerController. Логическая часть отстутсвует ввиду нехватки информации.