Введение 0:00 Приветствие и анонс нового видео о чистой архитектуре. Упоминание о предыдущем видео о криптовалюте и обещание новых видео при успехе текущего.
Особенности видео 0:44 Использование локальной базы данных Room вместо общедоступного API. Получение отзывов по последнему проекту и планы по улучшениям. Объяснение чистой архитектуры с нуля.
Интерфейс приложения 1:43 Описание пользовательского интерфейса приложения Node с Jetpack Compose. Примеры заметок с цветами и возможностью сортировки.
Создание и управление заметками 2:38 Процесс создания заметки: выбор цвета, заголовка и контента. Анимация затухания цвета при сохранении заметки. Возможность редактирования и удаления заметок.
Значение чистой архитектуры 4:33 Преимущества чистой архитектуры для портфолио и навыков. Различие между MVVM и чистой архитектурой. Принципы SOLID и новые подходы в чистой архитектуре.
Масштабируемость и тестирование 6:24 Важность масштабируемости и простоты расширения архитектуры. Лёгкость тестирования функций и замены компонентов. Пример перехода от Retrofit к Ktor.
Структура модулей 7:22 Эмуляция структуры модулей в Android с помощью пакетов. Фокус на структуре пакетов для понимания чистой архитектуры.
Начало работы 8:18 Регистрация на электронную рассылку для получения рекомендаций. Описание начального проекта с настроенными стилями и зависимостями. Ссылка на репозиторий на GitHub для загрузки проекта.
Настройка структуры пакета 9:08 Настройка структуры пакета для понимания работы чистой архитектуры. Закрытие вкладок для продолжения работы.
Введение в структуру пакета 9:59 Корневой пакет содержит пользовательский интерфейс и основные действия. Три основных уровня в чистой архитектуре: представление, данные и домен. Уровень представления содержит пользовательский интерфейс. Уровень данных отвечает за доступ к API, базе данных и общим настройкам. Уровень домена содержит бизнес-правила и логику, например, фильтрацию списка.
Преимущества многомодульной архитектуры 10:57 Многомодульная архитектура позволяет создавать небольшие и заменяемые модули. Маленькие модули ускоряют сборку приложения. Замена модулей становится проще при использовании нескольких функций.
Разделение приложения по функциям 11:54 Функция приложения — это набор экранов, например, отображение узлов, добавление заметок, удаление узлов. Каждая функция имеет свои уровни представления, домена и данных. Такое разделение облегчает понимание структуры приложения и его замену.
Практическое применение структуры 13:49 Создание пакета для функции node с именем feature_node. Разделение пакета на слои: представление, данные и домен. Важность абстракции источника данных, чтобы избежать зависимости от конкретной базы данных.
Создание пакетов данных и домена 14:47 Создание пакета данных с пакетом для источника данных. Создание пакета домена с пакетами модели, use case, репозитория и утилит.
Создание презентационного уровня 15:43 Создание пакета для каждого экрана: заметки и добавить узел редактирования. Добавление утилитарного пакета и компонентов для каждого экрана.
Дополнительные пакеты 17:41 Создание пакета di для внедрения зависимостей с помощью Dagger Hilt. Возможность создания пакета core для общих компонентов.
Реализация класса узла 18:33 Создание класса node в пакете model с полями: заголовок, тип содержимого, временная метка, цвет, идентификатор. Добавление сопутствующего объекта для управления цветами узлов.
Создание объекта доступа к данным 21:16 Создание интерфейса NodeDao для доступа к данным в базе Room. Определение функций для вставки, удаления, получения одного и всех узлов.
Определение функций DAO 21:45 Функция для получения всех узлов возвращает поток. Для работы функции требуется SQL-запрос «select * from nodes». Функция приостановки для получения узла по идентификатору.
Особенности функции приостановки 22:46 Идентификатор узла имеет тип integer. Функция возвращает узел с возможностью обнуления, при отсутствии узла возвращается null. Запрос для получения узла по идентификатору.
Функции вставки и удаления узлов 23:08 Функция вставки узла с стратегией предотвращения конфликтов «на замену». Функция удаления узла.
Создание класса базы данных 24:38 Абстрактный класс NodeDatabase с аннотацией базы данных. Определение таблицы узлов и версии базы данных. Наследование от RoomDatabase.
Роль репозитория 25:57 Репозиторий обращается к источникам данных API или база данных. Логика принятия решений о загрузке данных из кэша или API. Проверка ошибок и пересылка данных в варианты использования.
Интерфейс репозитория 26:45 Интерфейс NodeRepository для тестирования. Функции: getNodes, getNodeById, insertNode, deleteNode. Возможность создания поддельных версий репозитория для тестирования.
Реализация репозитория 28:38 Создание реализации репозитория узлов класса Kotlin. Реализация интерфейса NodeRepository.
Реализация репозитория 28:56 Репозиторий принимает параметр — объект DAO. Функции репозитория: getNotes, получение узла по идентификатору, вставка узла, удаление узла. В простом приложении репозиторий вызывает функции DAO, без сложной логики.
Введение в варианты использования 29:57 Варианты использования содержат бизнес-логику и делают код удобочитаемым. Каждый вариант использования отвечает за одно действие пользователя. Преимущества: быстрое понимание логики по названию класса, повторное использование кода.
Пример использования get nodes 31:49 Get nodes — самый сложный вариант использования. Возможность сортировки узлов по названию, цвету и дате. Создание класса GetNodes с интерфейсом репозитория.
Структура варианта использования 32:47 Один общедоступный метод в варианте использования. Метод возвращает поток списка узлов.
Служебные классы для сортировки 34:20 Создание классов TypeOrder и NodeOrder для определения типа заказа и способа сортировки. TypeOrder: восходящий или нисходящий. NodeOrder: по названию, дате или цвету.
Реализация сортировки узлов 37:05 Возврат потока со списком узлов из репозитория. Сопоставление списка узлов с отсортированным списком в зависимости от типа заказа. Использование функций сортировки по возрастанию и убыванию.
Детали сортировки 38:10 Сортировка по названию с переводом в нижний регистр. Сортировка по дате и цвету.
Повторное использование бизнес-логики 39:16 Бизнес-логика описывает доступ к хранилищу заметок. Класс вариантов использования можно повторно использовать во всём приложении. Это упрощает разработку и снижает количество логики в моделях представления.
Создание варианта использования для удаления узла 40:11 Создаём класс Kotlin под названием `deleteNodeUseCase`. В конструкторе вызываем репозиторий узлов и функцию оператора приостановки suspend. Функция удаляет узел, вызывая репозиторий с командой `deleteNode`.
Объединение вариантов использования 41:11 Объединяем варианты использования в один класс для упрощения конструктора ViewModel. Создаём класс `NodesUseCases` с описанием каждого варианта использования. Планируем расширить `deleteNodeUseCase` в будущем.
Настройка Dagger Hilt 42:05 Настраиваем библиотеку внедрения зависимостей Dagger Hilt. Регистрируем класс приложения в манифесте. Создаём модуль для предоставления зависимостей с заданным сроком службы.
Предоставление базы данных и репозитория 44:09 Предоставляем экземпляр базы данных комнат через функцию singleton. Используем контекст приложения для создания базы данных. Создаём репозиторий узлов, используя экземпляр базы данных и DAO.
Тестирование и поддельные зависимости 46:10 Для тестирования создаём отдельный модуль с поддельным репозиторием узлов. Внедрение зависимостей автоматически заменяет реальные зависимости на поддельные. Это позволяет тестировать классы без изменений в производственном приложении.
Завершение настройки 47:06 Предоставляем варианты использования узлов в модуле. Dagger Hilt автоматически внедряет зависимости, упрощая разработку.
Создание класса-оболочки и модели представления 47:20 Класс-оболочка предоставляет варианты использования узлов, используя экземпляр репозитория. Для get nodes и delete node возвращаются соответствующие варианты использования. Модель представления напрямую связана с пользовательским интерфейсом и выполняет роль презентатора в шаблоне MVP.
Задачи модели представления 48:16 Модель представления использует варианты использования для обработки бизнес-логики. Упорядоченный список узлов, полученный из базы данных, преобразуется в состояние, видимое пользовательскому интерфейсу. Создаётся класс NotesViewModel для управления состоянием пользовательского интерфейса.
Объект состояния 49:14 Объект состояния представляет текущее состояние пользовательского интерфейса на экране узла. Включает текущий порядок узлов, список узлов и состояние видимости раздела заказа. Создаётся класс NotesState для хранения этих данных.
Обработка действий пользователя 51:08 Модель представления обрабатывает все действия пользователя, такие как изменение порядка узлов, удаление заметки и восстановление узла. Для обработки событий создаётся класс-оболочка NodesEvent. События Order, Delete, Restore и ToggleOrder обрабатываются моделью представления.
Реализация событий 53:05 Событие Order передаётся из пользовательского интерфейса в модель представления при изменении порядка узлов. Событие Delete узла передаётся с указанием удалённого узла. Событие Restore узла используется для восстановления последнего удалённого узла.
Обновление состояния 54:38 Модель представления обновляет состояние узла при переключении раздела «Порядок». Переменная состояния инициализируется состоянием пустого узла. Логическое значение состояния обновляется для отображения раздела «Порядок».
Удаление и восстановление узла 56:13 При удалении узла вызывается вариант использования DeleteNode. Для восстановления узла сохраняется ссылка на последний удалённый узел в приватной переменной. Планируется использование варианта использования AddNode для добавления узла обратно в базу данных.
Создание варианта использования addnode 57:42 Создание варианта использования addnode, который принимает ссылку на репозиторий и узел для вставки. Проверка значений узла: название и содержимое. Вставка узла только при успешной проверке значений.
Обработка ошибок при вставке узла 58:37 Проверка пустого заголовка узла и выдача исключения. Создание класса исключений для обработки ошибок. Унаследование исключения от исходного исключения.
Проверка полей узла 59:39 Проверка пустого заголовка и содержимого узла. Возможность дополнительной проверки минимальной и максимальной длины полей.
Вставка узла и проверка исключений 1:00:17 Вставка узла при ложных утверждениях if. Проверка исключений в блоке try-catch. Использование вариантов использования узлов.
Событие передачи заметок 1:01:12 Добавление недавно удалённого узла. Присвоение недавно удалённому узлу значения null. Проверка изменения порядка заметок.
Сравнение классов для проверки порядка 1:01:59 Сравнение классов node order для проверки изменения порядка. Возврат текущего порядка при совпадении классов.
Функция для возврата узлов в заданном порядке 1:04:30 Возврат потока узлов из базы данных. Сопоставление потока с состоянием viewmodel. Запуск потока в viewmodel scope coutine.
Управление сопрограммами 1:05:26 Отмена старой сопрограммы при каждом вызове функции. Назначение нового задания для получения узлов. Загрузка узлов в порядке по умолчанию.
Создание экрана заметок 1:07:16 Создание переключателя и раздела «Порядок» для упорядочивания списка. Компоновка элементов экрана заметок.
Настройка параметров переключателя 1:08:15 Настройка текста, логического значения, функции проверки и модификатора для переключателя. Установка вертикального выравнивания и цветов переключателя.
Создание раздела заказа 1:09:57 Создание компонуемого раздела заказа с пятью переключателями. Передача модификатора для раздела заказа.
Порядок узлов и переключатели 1:11:01 Передача порядка узлов для определения проверяемых переключателей. По умолчанию порядок узлов определяется по убыванию. При изменении порядка узлов новый порядок передаётся в функцию обратного вызова родительскому компонуемому объекту.
Создание столбца переключателей 1:11:19 Создание столбца из двух строк: первая строка содержит три переключателя, вторая — два. Использование модификатора fillMaxWidth для первой строки. Жёсткое кодирование строк для простоты урока.
Настройка переключателей 1:12:19 Переключатели выбираются в зависимости от порядка узлов. При нажатии на переключатель «Название» запускается функция обратного вызова с новым порядком узлов. Копирование и вставка переключателей для других типов порядка.
Второй ряд переключателей 1:13:26 Установка вертикального пространства и модификатора fillMaxWidth для второго ряда. Копирование первых двух переключающих кнопок для сортировки по возрастанию. Сохранение текущего порядка узлов при изменении типа заказа.
Функция копирования порядка узлов 1:14:26 Создание функции copy для изменения типа заказа без использования классов данных. Возврат нового порядка узлов с изменённым типом заказа. Дублирование функции для переключателей «Дата» и «Цвет».
Создание элемента «узел» 1:16:10 Создание компонуемого элемента «узел» с параметрами: узел, модификатор, радиус угла. Настройка радиуса срезанного угла 30dp. Использование холста для рисования закруглённых углов и клипсы для обрезки края.
Работа с холстом 1:18:56 Создание коробки для рисования поверх холста. Применение модификатора canvas с родительским размером. Объяснение разницы между родительским размером и максимальным размером заливки.
Определение размера холста 1:19:53 Холсты требуют фиксированного размера при инициализации. Необходимость относительной единицы измерения для поддержки нескольких размеров экрана. Проверка размера коробки после размещения текстов для определения размера холста.
Введение в холст и курс 1:21:08 Обсуждение области для рисования на холсте. Рекомендация ознакомиться с курсом для более глубокого понимания холста.
Создание пути обрезки 1:22:08 Определение пути, огибающего прямоугольник с обрезанными углами. Использование контура обрезки для создания пути. Настройка координат x и y для начала пути.
Рисование круглых прямоугольников 1:22:56 Рисование большого круглого прямоугольника с цветом узла. Преобразование цвета в цвет композиции. Копирование и рисование маленького круглого прямоугольника с изменённым цветом.
Смешивание цветов 1:24:27 Применение операции смешивания цветов для затемнения. Определение соотношения смешивания и верхнего левого угла. Избегание округлений путём смещения угла.
Размещение текста и кнопки 1:26:34 Настройка отступов и стилей текста. Создание кнопки со значком для удаления узла. Применение модификатора для выравнивания кнопки.
Создание экрана заметок 1:28:36 Создание класса Kotlin для экрана заметок. Настройка параметров: navcontroller и viewmodel. Создание каркаса с плавающей кнопкой действия.
Реализация раздела «Порядок» 1:31:09 Настройка модификатора столбца и отступов. Добавление кнопки со значком для переключения порядка. Реализация анимации видимости раздела «Порядок».
Анимация раздела «Порядок» 1:32:42 Настройка анимации ввода и выхода раздела. Отправка события в viewmodel при изменении порядка узлов. Создание разделителя и отложенного столбца со списком заметок.
Работа с узлами и модификаторами 1:34:55 Использование перегрузки со списком элементов для передачи состояния. Добавление модификатора fillMaxWidth для интерактивности узлов. Реализация удаления узла при нажатии на кнопку «Удалить».
Отображение панели быстрого доступа 1:36:15 Использование сопрограммы для асинхронного отображения панели быстрого доступа. Проверка результата действия при нажатии на кнопку «Отменить». Добавление пространства между узлами.
Создание модели для получения узла 1:37:39 Создание варианта использования для получения узла по идентификатору. Добавление экземпляра в репозиторий и вызов функции оператора приостановки. Реализация модели представления для добавления узла.
Управление состояниями в модели представления 1:38:49 Определение необходимых состояний: текущий выбранный цвет, заголовок, содержимое. Создание отдельных состояний для каждого элемента пользовательского интерфейса. Разработка класса-оболочки для управления состоянием текстового поля.
Использование потока событий 1:42:51 Объяснение необходимости общего потока событий пользовательского интерфейса. Отправка разовых событий из viewmodel и их обработка в пользовательском интерфейсе. Примеры событий: показ закусочной, сохранение узла.
Настройка событий для редактирования узлов 1:45:02 Создание класса событий для редактирования узлов. Добавление событий для каждого действия пользовательского интерфейса. Настройка подсказок для ввода названия и содержимого узла.
События и состояния 1:46:18 Добавление события «добавленный узел». Обработка событий при фокусировке текстовых полей заголовка и содержимого. Использование состояния фокуса для скрытия подсказки.
События изменения цвета и сохранения узла 1:47:17 Добавление события изменения цвета узла. Сохранение узла при нажатии на плавающую кнопку действия. Различие событий в модели представления.
Обработка событий фокусировки 1:48:15 Обновление значения заголовка при фокусировке текстового поля. Отображение подсказки при отсутствии фокуса и пустом тексте.
События изменения содержимого и цвета 1:49:15 Обработка событий изменения содержимого узла. Выбор нового цвета узла при нажатии на цветной круг.
Сохранение узла 1:50:13 Запуск варианта использования добавления узла при сохранении. Проверка допустимости данных и генерация исключений при пустых заголовке или содержимом. Передача идентификатора узла для обновления существующего узла.
Получение текущего узла 1:53:17 Использование навигационных аргументов для получения идентификатора узла. Проверка идентификатора узла на равенство минус единице. Получение узла по идентификатору и обновление его данных в viewmodel.
Обновление данных узла 1:55:44 Обновление значения заголовка, содержимого и цвета узла. Извлечение данных узла из базы данных и отображение их в текстовом поле.
Создание пользовательского интерфейса 1:57:08 Создание прозрачного текстового поля с подсказкой. Настройка параметров текстового поля: текст, подсказка, модификатор, стиль текста. Установка функции изменения значения on и логического значения для однострочного текста.
Настройка текстового поля 1:58:20 Использование функции изменения фокуса для управления состоянием фокуса. Применение модификатора для стилизации текстового поля. Настройка отображения изменения значения при вводе.
Модификаторы и подсказки 1:59:12 Применение модификаторов single line и texttile. Использование модификатора fillmaxwidth для получения информации о состоянии фокуса. Отображение подсказки поверх текстового поля с тёмно-серым цветом.
Реализация экрана добавления заметок 2:00:33 Добавление экрана добавления заметок в пакет add added node. Настройка навигационного контроллера для перемещения назад при нажатии «Сохранить». Передача цвета узла в качестве аргумента навигации.
Анимация фона 2:01:51 Анимация фона с эффектом затухания цвета. Использование анимируемого свойства для изменения цвета фона. Проверка цвета узла для корректного отображения.
Создание плавающей кнопки действия 2:03:46 Создание плавающей кнопки действия с иконкой «сохранить заметку». Присвоение состояния scaffold для отображения элементов.
Настройка цветов узлов 2:05:41 Создание ряда для цветов узлов с модификатором fillmaxwidth. Настройка отступов и горизонтального расположения цветов. Создание кругов для каждого цвета с границей и тенью.
Кликабельность цветов и анимация 2:08:11 Присвоение кликабельности цветам узлов. Настройка анимации цвета при нажатии на цвет. Установка продолжительности анимации в 500 миллисекунд.
Текстовые поля и наблюдение за событиями 2:09:39 Настройка разделителя и прозрачного текстового поля с подсказками. Передача нового заголовка при изменении значения. Наблюдение за событиями пользовательского интерфейса через viewmodel eventflow.
Прокрутка страницы и события 2:12:07 Использование запущенного блока эффектов для прокрутки страницы вверх. Сбор последних данных через viewmodel eventflow. Обработка событий пользовательского интерфейса для отображения и скрытия элементов.
Настройка навигации и Snackbar 2:12:37 Сохраняем узел из события пользовательского интерфейса. Указываем состояние scaffold и хоста snackbar для отображения Snackbar. Вызываем navcontroller для перехода к экрану заметок.
Определение классов экранов и маршрутов 2:13:45 Определяем класс экрана для заметок и экрана добавления/редактирования заметок. Маршрут для экрана заметок — «на экран заметок». Аналогично для экрана добавления и редактирования заметок — «добавить добавленный экран заметок».
Настройка навигационного контроллера 2:14:07 Создаём навигационный контроллер 1-го уровня и navhost для определения экранов. Начинаем с пункта назначения — экрана импорта. Используем компонуемую функцию для определения различных экранов.
Передача аргументов в маршруты 2:15:00 Добавляем аргументы для маршрута: идентификатор узла и цвет узла. Аргументы необязательные, по умолчанию равны минус единице. Определяем навигационные аргументы с типами данных и значениями по умолчанию.
Тестирование приложения 2:18:17 Проверяем работу приложения в эмуляторе. Добавляем примечание и проверяем навигацию. Обновляем и сохраняем заметки, проверяем порядок узлов.
Завершение и призыв к взаимодействию 2:22:08 Приложение полностью работает. Автор благодарит зрителей и призывает оставлять комментарии и лайки. Предлагает подписаться на рассылку новостей и ознакомиться с платными курсами. Прощается с зрителями и желает хорошего дня.