From 276fa6c320a6eb0764c680d34a2c470139e1c59d Mon Sep 17 00:00:00 2001 From: Malik Date: Tue, 2 Jul 2019 14:06:17 +0300 Subject: [PATCH 01/17] Docs for livedata-location --- livedata-location/README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 livedata-location/README.md diff --git a/livedata-location/README.md b/livedata-location/README.md new file mode 100644 index 0000000..5789566 --- /dev/null +++ b/livedata-location/README.md @@ -0,0 +1,33 @@ +livedata-location +===== + +Модуль позволяющий получать местоположение пользователя в виде потока данных `LiveData`. + +### Основный интерфейсы и классы + +Класс `LocationLiveData`. В конструкторе принимает `Context` и `LocationRequest`. Посылает `Location` подписчикам через указанные в `LocationRequest` интервалы времени. Метод *observe* позволяет подписаться на эти обновления. Данный метод принимает `LifecycleOwner` и `Observer`. Стоит учесть, что для использования данного класса нужно одно из следующих разрешений `ACCESS_COARSE_LOCATION` или `ACCESS_FINE_LOCATION`. +### Примеры + +Во `ViewModel`. + +```kotlin +val locationWithInterval = LocationLiveData( + context, + LocationRequest + .create() + .setInterval(5000) + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) +) +``` + +Во `ViewController`. + +```kotlin +viewModel.locationWithInterval.observe(this, Observer(::onLocationChanged)) +``` + +### Подключение + +``` gradle +implementation project(':livedata-location') +``` \ No newline at end of file From 06f3650f44e993ba552864585d4e4a1447e29ee3 Mon Sep 17 00:00:00 2001 From: Malik Khiraev Date: Thu, 18 Jul 2019 14:23:48 +0300 Subject: [PATCH 02/17] Create README.md --- navigation/README.md | 129 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 navigation/README.md diff --git a/navigation/README.md b/navigation/README.md new file mode 100644 index 0000000..5e81e67 --- /dev/null +++ b/navigation/README.md @@ -0,0 +1,129 @@ +navigation +==== + +Модуль содержит классы для организации навигации в приложении. + +### Основные интерфейсы и классы + +#### Пакет `activities` + +Класс `BaseActivity` - абстрактный класс, в котором выполняется логгирование с помощью модуля [logging](https://github.com/TouchInstinct/RoboSwag/tree/master/logging) при выполнении некоторых методов. Класс позволяет добавлять новые `OnBackPressedListener` и удалять их с помощью методов *addOnBackPressedListener* и *removeOnBackPressedListener* (*removeAllOnBackPressedListeners*) соответственно. + +Интерфейс `OnBackPressedListener` - интерфейс с одним методом *onBackPressed*. Используется в `BaseActivity`. + +#### Пакет `fragments` + +Класс `ViewControllerFragment` является оберткой над `Fragment`. Через статический метод *args* получается `Bundle` с классом `ViewController`(а) и состоянием, которое наследуется от `Parcelable`. В методе *onCreate* инициализируются поля *state* и *viewControllerClass* используя данные из `Bundle`. В методе *onCreateView* создается `ViewController`. + +#### Пакет `viewcontrollers` + +Класс `EmptyState` - пустое состояние. Использутся, когда при переходе к новому `ViewController` не нужно передавать никаких инициализирующих данных. + +Класс `LifecycleLoggingObserver` - подписывается на вызовы методов жизненного цикла и логгирует номер строки из, которой был вызваны эти методы. + +Класс `ViewController` - Класс который следует использовать в качестве родительского при создании собственных `ViewController`(ов). К моменту инициализации вашего класса уже будут доступны следующие поля из `ViewController`: *activity*, *fragment*, *state*, *view*. Это означает, что можно выполнять всю настройку экрана в `init { }`. + +У класса есть два параметра `TActivity: FragmentActivity` и `TState: Parcelable`, которые нужно указывать при инициализации класса `ViewController`. В конструкторе данный класс принимает `CreationContext` и идентификатор layout-ресурса. + +Класс `ViewControllerNavigation` - навигация по `ViewController`(ам). В конструкторе принимает `Context`, `FragmentManager` и идентификатор ресурса, который является контейнером для других фрагментов. Имеет параметр `TActivity : FragmentActivity`. + +Методы для навигации: + +* *pushViewController* добавляет `ViewController` в стек. Имеет два обязательных параметра *viewControllerClass* - класс, унаследованный от `ViewController` и *state* - объект описывающий состояние. + +* *pushViewControllerForResult* аналогичен предыдущему методу, используется, когда необходимо запустить какой-то фрагмент и при его завершении получить код. Для этого передаются еще два параметра: *requestCode* - код, который нужно получить при закрытии фрагмента и *targetFragment* - фрагмент, который должен получить этот код. + +* *setViewControllerAsTop* работает так же как и *pushViewController* но еще добавляет в качестве *backStackName* тег `TOP_FRAGMENT_TAG_MARK`. При выполнении возврата с помощью метода `up` будет выполнен возврат данному фрагменту. + +* *setInitialViewController* очищает стек и добавляет туда переданный `ViewController`. + +`ViewControllerNavigation` является наследником класса `FragmentNavigation` и для возвратов необходимо использоать методы из родительского класса: + +* *back* - вернуться к фрагменту, который лежит ниже в стеке. +* *up* - вернуться к самому низу стека, если в стеке нет фрагментов, помеченных тегом `TOP_FRAGMENT_TAG_MARK`. Если есть, то выполнить возврат к нему. Имеет два необязательных параметра: *name* - имя класса до которого нужно сделать возврат, если он не будет найден, то будет произведен возврат к самому низу стека; *inclusive* - если установить этот флаг, то будет произведен возврат к самому низу стека несмотря на фрагменты с тегом `TOP_FRAGMENT_TAG_MARK`. Если будет установлен и *name* и *inclusive*, то будет произведен возврат к фрагменту, который стоит ниже фрагмента с переданным *name*. + +### Примеры + +Файл `MainActivity.kt` +```Kotlin +class MainActivity : BaseActivity() { + + private val screenNavigation by lazy { + ViewControllerNavigation( + this, + supportFragmentManager, + R.id.fragment_container + ) + } + + fun getNavigation() = screenNavigation + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + screenNavigation.setInitialViewController( + MainViewController::class.java, + MainScreenState(true) + ) + } + +} +``` + +Файл `MainViewController.kt` +```Kotlin +class MainViewController( + creationContext: CreationContext +) : ViewController( + creationContext, + R.layout.view_controller_main +) { + + private val button: View = findViewById(R.id.view_controller_main_button) + + init { + button.setOnClickListener { + activity.getNavigation().pushViewController( + TutorialViewController::class.java, + EmptyState + ) + } + } + +} +``` + +Файл `activity_main.xml` +```xml + + + + + + +``` + +### Рекомендации + +Рекомендуется делать состояния, которые передаются во `ViewController` неизменяемыми, чтобы при навигации обратно `ViewController` корректно восстанавливались с изначально заданным состоянием. + +### Зависимости + +Для работы с данным модулем необходимо так же подключить модуль [logging](https://github.com/TouchInstinct/RoboSwag/tree/master/logging). + +```gradle +implementation project(':logging') +``` + +### Подключение + +```gradle +implementation project(':navigation') +``` From 606ec242315226c9515cd9fbf751eeaf07e8d54c Mon Sep 17 00:00:00 2001 From: Malik Khiraev Date: Thu, 18 Jul 2019 14:48:48 +0300 Subject: [PATCH 03/17] Create README.md --- recyclerview-adapters/README.md | 64 +++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 recyclerview-adapters/README.md diff --git a/recyclerview-adapters/README.md b/recyclerview-adapters/README.md new file mode 100644 index 0000000..7085683 --- /dev/null +++ b/recyclerview-adapters/README.md @@ -0,0 +1,64 @@ +recyclerview-adapters +===== + +Модуль, расширяющий возможности работы со стандартным `RecyclerView.Adapter`. + +### Основные интерфейсы и классы + +`DelegationListAdapter` - базовый класс, наследник от `RecyclerView.Adapter`. Управлением элементами списка занимаются делегаты. Они добавляются с помощью метода *addDelegate*. Конструктор принимает `DiffUtil.ItemCallback` - интерфейс, описывающий как различать элементы в адаптере, содержит два абстрактных метода: *areItemsTheSame* - метод, сравнивающий элементы, и *areContentsTheSame* - метод, сравнивающий визуальную составляющую элементов. Возьмем, например, список товаров, у которых есть уникальный *id* и *title*, который может повторяться. В `RecyclerView` отображается только название товара, т.е. *title*. В такой ситуации в методе *areItemsTheSame* нужно будет написать `oldItem.id == newItem.id`, а в методе *areContentsTheSame* - `oldItem.title == newItem.title`. Оба эти метода вычисляются в бэкграунд потоке. Методы `getHeadersCount` и `getFootersCount` нужны, когда в списке есть элементы, которые всегда должны быть наверху или внизу. Например, если нужно добавить кнопку после всех элементов. + +`ItemAdapterDelegate` - делегат, который управляет созданием и прикреплением элементов в зависимости от типа элемента. + +`PositionAdapterDelegate` - делегат, который управляет созданием и прикреплением элементов, основываясь на позиции элемента в `DelegationListAdapter`. + +При реализации делегатов, необходимо описать два метода: +* *isForViewType* - метод, который говорит делегату, должен ли он управлять соответсвующим элементом; +* *onBindViewHolder* - метод, который описывает действия при прикреплении элемента к `ViewHolder`. + +### Примеры + +Создание адаптера. + +```Kotlin +class SomeAdapter : DelegationListAdapter(CALLBACK) { + + companion object { + private val CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Item, newItem: Item) = newItem.id == oldItem.id + override fun areContentsTheSame(oldItem: Item, newItem: Item) = newItem == oldItem + } + } + + init { + addDelegate(HeaderDelegate()) + addDelegate(ItemDelegate()) + addDelegate(BottomDelegate()) + } + + // Some logic in your adapter +} +``` + +Создание делегата. +```Kotlin +class HeaderDelegate( + private val addAction: () -> Unit +) : PositionAdapterDelegate() { + + override fun isForViewType(adapterPosition: Int): Boolean = adapterPosition == 0 + + override fun onCreateViewHolder(parent: ViewGroup) = + object : RecyclerView.ViewHolder(HeaderItemView()) {} + + override fun onBindViewHolder( + holder: RecyclerView.ViewHolder, + adapterPosition: Int, + payloads: MutableList + ) = holder.itemView.setOnClickListener { addAction.invoke() } +} +``` + +### Подключение +```gralde +implementation project(':recyclerview-adapters') +``` From ccdf00c789028204b4cba68761c7e22296a302f2 Mon Sep 17 00:00:00 2001 From: Malik Khiraev Date: Thu, 18 Jul 2019 14:50:19 +0300 Subject: [PATCH 04/17] Create README.md --- lifecycle-rx/README.md | 56 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 lifecycle-rx/README.md diff --git a/lifecycle-rx/README.md b/lifecycle-rx/README.md new file mode 100644 index 0000000..c80e185 --- /dev/null +++ b/lifecycle-rx/README.md @@ -0,0 +1,56 @@ +lifecycle-rx +===== + +Модуль для преобразования событий из `Flowable`, `Observable`, `Single`, `Completable`, `Maybe` в `LiveData`. Нужен для передачи событий из `ViewModel` во `ViewController` с автоматическим управлением подписками во `ViewController`. + +### Основный интерфейсы и классы +`Destroyable` - интерфейс, который содержит extansion-функцию *untilDestroy* для `Flowable`, `Observable`, `Single`, `Completable`, `Maybe`. Данная функция гарантирует, что подписка на события "умрет" после *onDestroy*. + +`LifeDataDispatcher` - интерфейс, описывающий функцию *dispatchTo* для преобразования `Observable` в `MutableLiveData`. + +`BaseDestroyable` и `BaseLifeDataDispatcher` - базовые реализации `Destroyable` и `LifeDataDispatcher` соответсвенно. + +`RxViewModel` - базовый класс, от которого должны наследоваться все `ViewModel`. Обеспечивает отписку всех подписчиков при возникновении *onCleared*. Реализует `BaseDestroyable` и `LiveDataDispatcher`. По умолчанию использует базовые реализации данных интерфейсов, при желании можно передать свои `Destroyable` и `LiveDataDispatcher` через конструктор. + +### Примеры + +Простой пример `ViewModel`, через который можно получить список элементов и добавить один элемент. + +```kotlin +class SomeViewModel ( + private val someRepository: SomeRepository +) : RxViewModel() { + + val itemsList = MutableLiveData>>() + + fun getItemsList() { + someRepository + .getItems() + .dispatchTo(itemsList) + } + + fun addItem(item: Item) { + someRepository + .addItem(item) + .untilDestroy() + } +} +``` + +Подписка на события во `ViewController`. `ContentEvent` описан в модуле [lifecycle](https://github.com/TouchInstinct/RoboSwag/tree/master/lifecycle). + +```kotlin +someViewModel.itemsList.observe(this, Observer { event -> + when (event) { + is ContentEvent.Loading -> // do something + is ContentEvent.Success -> // do something + is ContentEvent.Error -> // do something + } +}) +``` + +### Подключение + +``` gradle +implementation project(':lifecycle-rx') +``` From e26fd89882bd25c47b8e35a7f7186a7b7bb5060b Mon Sep 17 00:00:00 2001 From: Malik Khiraev Date: Fri, 19 Jul 2019 12:39:44 +0300 Subject: [PATCH 05/17] Docs for lifecycle (#34) --- lifecycle/README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 lifecycle/README.md diff --git a/lifecycle/README.md b/lifecycle/README.md new file mode 100644 index 0000000..1c265cf --- /dev/null +++ b/lifecycle/README.md @@ -0,0 +1,49 @@ +lifecycle +===== + +Модуль содержит обертку над `ViewModelProviders` для работы с `ViewController` и обертки для передачи событий из `ViewModel` во `ViewController`. + +### Основные интерфейсы и классы + +`LifecycleViewModelProviders` - объект для получения `ViewModelProvider`. Содержит функцию *of*, которая принимает `LifecycleOwner` и возвращает специфичный для него `ViewModelProvider`. + +`SingleLiveEvent` - событие - одиночка. Посылает события только один раз. Наследуется от `MutableLiveData` и переопределяет методы `observe` и `setValue`. + +`ContentEvent` - событие, обертка над данными. +Дочерние классы: +* `Loading` - символизирует состояние загрузки, +* `Success` - символизирует успешное событие, +* `Error` - символизирует ошибку, +* `Complete` - символизирует завершение события. + +`Event` - аналогичен `ContentEvent`, только не содержит никакой информации о данных. Нужен для оповещения о наступлении одного из следующих событий: `Loading`, `Complete` или `Error`. + +### Примеры + +Получение `ViewModel` во `ViewController`. + +```kotlin +private val viewModel = LifecycleViewModelProviders.of(this).get(SomeViewModel::class.java) +``` + +Подписка на `SingleLiveEvent`. + +```kotlin +// во ViewModel +val event = SingleLiveEvent() + +// во ViewController +event.observe(this, Observer { event -> + when (event) { + is Event.Loading -> ::onEventLoading + is Event.Complete -> ::onEventComplete + is Event.Error -> ::onEventError + } +}) +``` + +### Подключение + +```gradle +implementation project(':lifecycle') +``` From 82e21f606a80429e8c2cb7c9dd3d826dbf5963d0 Mon Sep 17 00:00:00 2001 From: Malik Khiraev Date: Wed, 31 Jul 2019 13:24:50 +0300 Subject: [PATCH 06/17] Update README.md --- navigation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/navigation/README.md b/navigation/README.md index 5e81e67..14bc824 100644 --- a/navigation/README.md +++ b/navigation/README.md @@ -21,7 +21,7 @@ navigation Класс `LifecycleLoggingObserver` - подписывается на вызовы методов жизненного цикла и логгирует номер строки из, которой был вызваны эти методы. -Класс `ViewController` - Класс который следует использовать в качестве родительского при создании собственных `ViewController`(ов). К моменту инициализации вашего класса уже будут доступны следующие поля из `ViewController`: *activity*, *fragment*, *state*, *view*. Это означает, что можно выполнять всю настройку экрана в `init { }`. +Класс `ViewController` - Класс который следует использовать в качестве родительского при создании собственных `ViewController`(ов). К моменту инициализации вашего класса уже будут доступны следующие поля из `ViewController`: *state*, *activity*, *fragment*, *view*. Это означает, что можно выполнять всю настройку экрана в `init { }`. У класса есть два параметра `TActivity: FragmentActivity` и `TState: Parcelable`, которые нужно указывать при инициализации класса `ViewController`. В конструкторе данный класс принимает `CreationContext` и идентификатор layout-ресурса. From 966acffd065d7ad1f7fe711f0fdda53ca03fe0fe Mon Sep 17 00:00:00 2001 From: Malik Khiraev Date: Fri, 2 Aug 2019 15:05:09 +0300 Subject: [PATCH 07/17] Docs for kotlin-extensions (#27) --- kotlin-extensions/README.md | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 kotlin-extensions/README.md diff --git a/kotlin-extensions/README.md b/kotlin-extensions/README.md new file mode 100644 index 0000000..7e23a7a --- /dev/null +++ b/kotlin-extensions/README.md @@ -0,0 +1,67 @@ +kotlin-extensions +===== + +Модуль содержит extension-функции для `Activity`, `Context`, `Delegates`, `TextView`, `View` и `ViewHolder`. + +### Основные интерфейсы и классы + +##### Расширения для `Activity`: + +* *safeStartActivityForResult* - функция для запуска нового активити с `requestCode`, который будет передан в *onActivityResult* при завершении работы данного активити. Находит наиболее подходящий активити для выполнения действия. Если не будет найден ни один активити для выполнения действия, то функция ничего не сделает и вернет `false`. + +##### Расширения для `Context`: + +* *safeStartActivity* - функция запуска активити, аналогична *safeStartActivityForResult*, но не позволяет передать `requestCode`. + +* *openBrowser* - функция для открытия ссылки в браузере через *safeStartActivity*. + +* *callToPhoneNumber* - функция для открытия программы "Телефон" с переданным номером телефона через *safeStartActivity*. + +##### Расширения для `TextView`: + +* *drawableStart*, *drawableTop*, *drawableEnd*, *drawableBottom* - функции для установки и получения `Drawable` на соответсвующих позициях. + +##### Расширения для `View`: + +* *setOnRippleClickListener* - функция для добавления Ripple-эффекта и действия, которое будет выполняться при нажатии на `View`. + +##### Расширения для `ViewHolder`: + +* *ViewHolder.findViewById* - функция для поиска `View`, расположеного внутри *itemView*. + +* *ViewHolder.getText* - функция для получения текста из ресурсов. + +* *ViewHolder.getString* - функция для получения строк из ресурсов. Может также принимать вторым аргументом и далее - строки, которые будут подставлены вместо специальных символов в строку из ресурсов. + +* *ViewHolder.getColor* - получить цвет в виде `Int` из ресурсов. + +* *ViewHolder.getColorStateList* - получить `ColorStateList`, который ассоциируется с переданным цветом. + +* *ViewHolder.getDrawable* - получить `Drawable` из ресурсов. + +##### Расширения для `Delegates`: + +* *observable* - подписка на изменения свойства, принимает `initialValue` - начальное значение и `onChange` - действие, которое будет выполняться после каждой установки свойства. + +* *distinctUntilChanged* - тоже самое, что и предыдущее расширение, только `onChange` будет выполняться лишь в том случае, когда свойство принимает новое значение не равное `null` и отличное от предыдущего. + +### Примеры + +```kotlin +class LinkViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + + private val linkView: TextView = findViewById(R.id.item_link) + private val linkColor = getColor(R.color.global_action) + + fun bind(link: String) { + linkView.text = link + linkView.setOnRippleClickListener { context.openBrowser(link) } + } +} +``` + +### Подключение + +```gradle +implementation project(':kotlin-extensions') +``` From 30dd180fb946e65c8403d4df97c7d47ee8584993 Mon Sep 17 00:00:00 2001 From: Maxim Bachinsky Date: Fri, 2 Aug 2019 16:12:13 +0300 Subject: [PATCH 08/17] new main page docs --- README.md | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6e9bfd3..ebcb47f 100644 --- a/README.md +++ b/README.md @@ -1 +1,82 @@ -# RoboSwag \ No newline at end of file +# RoboSwag +Roboswag - библиотека решений, ускоряющих разработку Android приложений. Оно включает в себя архитектурные решения для построения приложения, утилитарные классы и общие инструменты, которые используются в компании Touch Instinct. +Библиотека состоит из gradle модулей. Каждый модуль отвечает за свой функционал. В проектах используются только те модули, которые нужны. Такая модульность позволяет сохранять размер приложения небольшим и ускорять сборку проекта. + +## Минимальные требования + +* Andoroid Api: 19 +* Kotlin: 1.3.11 +* Gradle: 3.2.1 +* Gradle CPD Plugin: 1.1 +* Detekt Plugin: 1.0.0-RC12 + +## Основная архитектура +За основу архитектуры взят подход от Google - MVVM на основе [Android Architecture Components](https://developer.android.com/jetpack/docs/guide). Данный подход популярен в сообществе Android разработки, позволяет разбивать код на мелкие и независимые части, что ускоряет разработку и последующую поддержку приложения. +Для организации многопоточности используется фреймворк [RxJava2](https://github.com/ReactiveX/RxJava). RxJava - обширный инструмент, реализующий концепции реактивного программирования. Сочетание этой концепции с возможностью выносить задачи на другой поток позволяет легко писать многопоточное асинхронное приложение. +В качестве Di-фреймворка выбран [Dagger 2](https://github.com/google/dagger). Он позволяет сделать код приложения менее связным, более гибким и позволяет легко настроить автотестирование. +Roboswag позволяет сочитать эти три решения в одну гибкую и удобную архитектуру. Разработка становится быстрее, проще и надежнее. За архитектуру отвечают модули [lifecycle](/lifecycle) и [lifecycle-rx](/lifecycle-rx). + +## Основные инструменты библиотеки +### Работа с RecyclerView +RecyclerView - один из самых часто используемых инструментов Android разработчика. Модуль [recyclerview-adapters](/recyclerview-adapters) позволяет сделать работу с RecyclerView более гибкой и делает работу самого элемента быстрее. +### BuildScripts +[BuildScrpts](/Buildscripts) - набор скриптов, автоматизирующих разработку. Один из главных скриптов - staticAnalysis - инструмент для автоматической проверки кода на соответствие правилам компании. +### Api Generator +Внутренний инструмент компании Touch Instinct для генерации общего кода на разные платформы - Android, IOs и Server. Описанные в одном месте общие классы и Http методы используются на разных платформах. Данный инструмент позволяет сократить время разработки в два раза. +### Работа с SharedPreferences +Чтобы сохранять простые данные в память смартфона, используются SharedPreferences. Модуль [storables](/storables) разработан для облегчения работы с SharedPreferences. +### Утилиты и extension функции +В Roboswag также есть много [утилитарных](/utils) классов или [extension](/kotlin-extensions) функций, которые позволяют писать часто используемый код в одну строку. + +### Подключение + +#### .gitmodules + +``` +[submodule "RoboSwag"] + path = RoboSwag + url = git@github.com:TouchInstinct/RoboSwag.git +``` + +#### build.gradle (Module: app) + +```gradle +dependencies { + implementation project(':utils') + implementation project(':views') + implementation project(':storable') + implementation project(':logging') + implementation project(':api-logansquare') + implementation project(':lifecycle') + implementation project(':lifecycle-rx') + implementation project(':navigation') + implementation project(':templates') + implementation project(':recyclerview-adapters') + implementation project(':recyclerview-calendar') + implementation project(':kotlin-extensions') + implementation project(':livedata-location') +} +``` +Можно подключать только те модули, которые вам необходимы. + +### R8/Proguard + +``` +-keep class ** extends ru.touchin.roboswag.components.navigation.viewcontrollers.ViewController { *; } +``` + +### Лицензия + +``` +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` From 02d8178939983798b6f54b1dace07d3a80220140 Mon Sep 17 00:00:00 2001 From: Maxim Bachinsky Date: Fri, 2 Aug 2019 16:16:31 +0300 Subject: [PATCH 09/17] fix refs on readme page --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ebcb47f..5e31d0a 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,11 @@ Roboswag позволяет сочитать эти три решения в о ### Работа с RecyclerView RecyclerView - один из самых часто используемых инструментов Android разработчика. Модуль [recyclerview-adapters](/recyclerview-adapters) позволяет сделать работу с RecyclerView более гибкой и делает работу самого элемента быстрее. ### BuildScripts -[BuildScrpts](/Buildscripts) - набор скриптов, автоматизирующих разработку. Один из главных скриптов - staticAnalysis - инструмент для автоматической проверки кода на соответствие правилам компании. +[BuildScrpts](https://github.com/TouchInstinct/BuildScripts) - набор скриптов, автоматизирующих разработку. Один из главных скриптов - staticAnalysis - инструмент для автоматической проверки кода на соответствие правилам компании. ### Api Generator Внутренний инструмент компании Touch Instinct для генерации общего кода на разные платформы - Android, IOs и Server. Описанные в одном месте общие классы и Http методы используются на разных платформах. Данный инструмент позволяет сократить время разработки в два раза. ### Работа с SharedPreferences -Чтобы сохранять простые данные в память смартфона, используются SharedPreferences. Модуль [storables](/storables) разработан для облегчения работы с SharedPreferences. +Чтобы сохранять простые данные в память смартфона, используются SharedPreferences. Модуль [storables](/storable) разработан для облегчения работы с SharedPreferences. ### Утилиты и extension функции В Roboswag также есть много [утилитарных](/utils) классов или [extension](/kotlin-extensions) функций, которые позволяют писать часто используемый код в одну строку. From 39045ce1c264acaabc1a4673f8b4f653ac728004 Mon Sep 17 00:00:00 2001 From: Maxim Bachinsky Date: Fri, 2 Aug 2019 16:23:15 +0300 Subject: [PATCH 10/17] fix comments --- navigation/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/navigation/README.md b/navigation/README.md index 14bc824..7ceb977 100644 --- a/navigation/README.md +++ b/navigation/README.md @@ -7,25 +7,25 @@ navigation #### Пакет `activities` -Класс `BaseActivity` - абстрактный класс, в котором выполняется логгирование с помощью модуля [logging](https://github.com/TouchInstinct/RoboSwag/tree/master/logging) при выполнении некоторых методов. Класс позволяет добавлять новые `OnBackPressedListener` и удалять их с помощью методов *addOnBackPressedListener* и *removeOnBackPressedListener* (*removeAllOnBackPressedListeners*) соответственно. +`BaseActivity` - абстрактный класс, в котором выполняется логгирование с помощью модуля [logging](https://github.com/TouchInstinct/RoboSwag/tree/master/logging) при выполнении некоторых методов. Класс позволяет добавлять новые `OnBackPressedListener` и удалять их с помощью методов *addOnBackPressedListener* и *removeOnBackPressedListener* (*removeAllOnBackPressedListeners*) соответственно. Интерфейс `OnBackPressedListener` - интерфейс с одним методом *onBackPressed*. Используется в `BaseActivity`. #### Пакет `fragments` -Класс `ViewControllerFragment` является оберткой над `Fragment`. Через статический метод *args* получается `Bundle` с классом `ViewController`(а) и состоянием, которое наследуется от `Parcelable`. В методе *onCreate* инициализируются поля *state* и *viewControllerClass* используя данные из `Bundle`. В методе *onCreateView* создается `ViewController`. +Класс `ViewControllerFragment` наследуется от `Fragment`. Через статический метод *args* получается `Bundle` с классом `ViewController`(а) и состоянием, которое наследуется от `Parcelable`. В методе *onCreate* инициализируются поля *state* и *viewControllerClass* используя данные из `Bundle`. В методе *onCreateView* создается `ViewController`. #### Пакет `viewcontrollers` -Класс `EmptyState` - пустое состояние. Использутся, когда при переходе к новому `ViewController` не нужно передавать никаких инициализирующих данных. - -Класс `LifecycleLoggingObserver` - подписывается на вызовы методов жизненного цикла и логгирует номер строки из, которой был вызваны эти методы. - -Класс `ViewController` - Класс который следует использовать в качестве родительского при создании собственных `ViewController`(ов). К моменту инициализации вашего класса уже будут доступны следующие поля из `ViewController`: *state*, *activity*, *fragment*, *view*. Это означает, что можно выполнять всю настройку экрана в `init { }`. +`ViewController` - обертка над Fragment. Один ViewController - один экран. К моменту инициализации вашего класса уже будут доступны следующие поля из `ViewController`: *state*, *activity*, *fragment*, *view*. Это означает, что можно выполнять всю настройку экрана в `init { }`. У класса есть два параметра `TActivity: FragmentActivity` и `TState: Parcelable`, которые нужно указывать при инициализации класса `ViewController`. В конструкторе данный класс принимает `CreationContext` и идентификатор layout-ресурса. -Класс `ViewControllerNavigation` - навигация по `ViewController`(ам). В конструкторе принимает `Context`, `FragmentManager` и идентификатор ресурса, который является контейнером для других фрагментов. Имеет параметр `TActivity : FragmentActivity`. +`ViewControllerNavigation` отвечает за навигацию по `ViewController`(ам). В конструкторе принимает `Context`, `FragmentManager` и идентификатор ресурса, который является контейнером для других фрагментов. Имеет параметр `TActivity : FragmentActivity`. + +`EmptyState` - пустое состояние. Использутся, когда при переходе к новому `ViewController` не нужно передавать никаких инициализирующих данных. + +`LifecycleLoggingObserver` - подписывается на вызовы методов жизненного цикла и логгирует номер строки из, которой был вызваны эти методы. Методы для навигации: From 2a34cd5f6625522eaac486597c614df1a6f9a50c Mon Sep 17 00:00:00 2001 From: Maxim Bachinsky Date: Fri, 2 Aug 2019 16:23:41 +0300 Subject: [PATCH 11/17] little fix --- navigation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/navigation/README.md b/navigation/README.md index 7ceb977..fb3f6f3 100644 --- a/navigation/README.md +++ b/navigation/README.md @@ -25,7 +25,7 @@ navigation `EmptyState` - пустое состояние. Использутся, когда при переходе к новому `ViewController` не нужно передавать никаких инициализирующих данных. -`LifecycleLoggingObserver` - подписывается на вызовы методов жизненного цикла и логгирует номер строки из, которой был вызваны эти методы. +`LifecycleLoggingObserver` подписывается на вызовы методов жизненного цикла и логгирует номер строки из, которой был вызваны эти методы. Методы для навигации: From 3a3f997d91d051c772faf9103a759609faf1b6d9 Mon Sep 17 00:00:00 2001 From: Maxim Bachinsky Date: Fri, 2 Aug 2019 16:24:33 +0300 Subject: [PATCH 12/17] one more little fix --- navigation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/navigation/README.md b/navigation/README.md index fb3f6f3..21b18bf 100644 --- a/navigation/README.md +++ b/navigation/README.md @@ -37,7 +37,7 @@ navigation * *setInitialViewController* очищает стек и добавляет туда переданный `ViewController`. -`ViewControllerNavigation` является наследником класса `FragmentNavigation` и для возвратов необходимо использоать методы из родительского класса: +`ViewControllerNavigation` является наследником класса `FragmentNavigation` и для возвратов необходимо использовать методы из родительского класса: * *back* - вернуться к фрагменту, который лежит ниже в стеке. * *up* - вернуться к самому низу стека, если в стеке нет фрагментов, помеченных тегом `TOP_FRAGMENT_TAG_MARK`. Если есть, то выполнить возврат к нему. Имеет два необязательных параметра: *name* - имя класса до которого нужно сделать возврат, если он не будет найден, то будет произведен возврат к самому низу стека; *inclusive* - если установить этот флаг, то будет произведен возврат к самому низу стека несмотря на фрагменты с тегом `TOP_FRAGMENT_TAG_MARK`. Если будет установлен и *name* и *inclusive*, то будет произведен возврат к фрагменту, который стоит ниже фрагмента с переданным *name*. From 96d3e39aafebf7c6d5c3947582a16fe3adfc0a46 Mon Sep 17 00:00:00 2001 From: Maxim Bachinsky Date: Fri, 2 Aug 2019 16:27:51 +0300 Subject: [PATCH 13/17] little text refactor --- recyclerview-adapters/README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/recyclerview-adapters/README.md b/recyclerview-adapters/README.md index 7085683..3328fe7 100644 --- a/recyclerview-adapters/README.md +++ b/recyclerview-adapters/README.md @@ -1,11 +1,18 @@ -recyclerview-adapters -===== +# recyclerview-adapters Модуль, расширяющий возможности работы со стандартным `RecyclerView.Adapter`. ### Основные интерфейсы и классы -`DelegationListAdapter` - базовый класс, наследник от `RecyclerView.Adapter`. Управлением элементами списка занимаются делегаты. Они добавляются с помощью метода *addDelegate*. Конструктор принимает `DiffUtil.ItemCallback` - интерфейс, описывающий как различать элементы в адаптере, содержит два абстрактных метода: *areItemsTheSame* - метод, сравнивающий элементы, и *areContentsTheSame* - метод, сравнивающий визуальную составляющую элементов. Возьмем, например, список товаров, у которых есть уникальный *id* и *title*, который может повторяться. В `RecyclerView` отображается только название товара, т.е. *title*. В такой ситуации в методе *areItemsTheSame* нужно будет написать `oldItem.id == newItem.id`, а в методе *areContentsTheSame* - `oldItem.title == newItem.title`. Оба эти метода вычисляются в бэкграунд потоке. Методы `getHeadersCount` и `getFootersCount` нужны, когда в списке есть элементы, которые всегда должны быть наверху или внизу. Например, если нужно добавить кнопку после всех элементов. +`DelegationListAdapter` - базовый класс, наследник от `RecyclerView.Adapter`. + +Конструктор принимает `DiffUtil.ItemCallback` - интерфейс, описывающий как различать элементы в адаптере. Он содержит два абстрактных метода: *areItemsTheSame* - метод, сравнивающий элементы, и *areContentsTheSame* - метод, сравнивающий визуальную составляющую элементов. + +Например, возьмем список товаров, у которых есть уникальный *id* и *title*, который может повторяться. В `RecyclerView` отображается только название товара, т.е. *title*. В такой ситуации в методе *areItemsTheSame* нужно будет написать `oldItem.id == newItem.id`, а в методе *areContentsTheSame* - `oldItem.title == newItem.title`. Оба эти метода вычисляются в бэкграунд потоке. + +Методы `getHeadersCount` и `getFootersCount` нужны, когда в списке есть элементы, которые всегда должны быть наверху или внизу. Например, если нужно добавить кнопку после всех элементов. + +Управлением элементами списка занимаются делегаты. Они добавляются с помощью метода *addDelegate*. `ItemAdapterDelegate` - делегат, который управляет созданием и прикреплением элементов в зависимости от типа элемента. From 2b32c0261899d7de7277ebe27f6809dcf037a92a Mon Sep 17 00:00:00 2001 From: Maxim Bachinsky Date: Fri, 2 Aug 2019 16:57:32 +0300 Subject: [PATCH 14/17] fix comments --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5e31d0a..13e655f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # RoboSwag -Roboswag - библиотека решений, ускоряющих разработку Android приложений. Оно включает в себя архитектурные решения для построения приложения, утилитарные классы и общие инструменты, которые используются в компании Touch Instinct. +Roboswag - библиотека решений, ускоряющих разработку Android приложений. Она включает в себя архитектурные решения для построения приложения, утилитарные классы и общие инструменты, которые используются в компании Touch Instinct. Библиотека состоит из gradle модулей. Каждый модуль отвечает за свой функционал. В проектах используются только те модули, которые нужны. Такая модульность позволяет сохранять размер приложения небольшим и ускорять сборку проекта. ## Минимальные требования @@ -14,7 +14,7 @@ Roboswag - библиотека решений, ускоряющих разра За основу архитектуры взят подход от Google - MVVM на основе [Android Architecture Components](https://developer.android.com/jetpack/docs/guide). Данный подход популярен в сообществе Android разработки, позволяет разбивать код на мелкие и независимые части, что ускоряет разработку и последующую поддержку приложения. Для организации многопоточности используется фреймворк [RxJava2](https://github.com/ReactiveX/RxJava). RxJava - обширный инструмент, реализующий концепции реактивного программирования. Сочетание этой концепции с возможностью выносить задачи на другой поток позволяет легко писать многопоточное асинхронное приложение. В качестве Di-фреймворка выбран [Dagger 2](https://github.com/google/dagger). Он позволяет сделать код приложения менее связным, более гибким и позволяет легко настроить автотестирование. -Roboswag позволяет сочитать эти три решения в одну гибкую и удобную архитектуру. Разработка становится быстрее, проще и надежнее. За архитектуру отвечают модули [lifecycle](/lifecycle) и [lifecycle-rx](/lifecycle-rx). +Roboswag позволяет сочетать эти три решения в одну гибкую и удобную архитектуру. Разработка становится быстрее, проще и надежнее. За архитектуру отвечают модули [lifecycle](/lifecycle) и [lifecycle-rx](/lifecycle-rx). ## Основные инструменты библиотеки ### Работа с RecyclerView @@ -22,9 +22,9 @@ RecyclerView - один из самых часто используемых ин ### BuildScripts [BuildScrpts](https://github.com/TouchInstinct/BuildScripts) - набор скриптов, автоматизирующих разработку. Один из главных скриптов - staticAnalysis - инструмент для автоматической проверки кода на соответствие правилам компании. ### Api Generator -Внутренний инструмент компании Touch Instinct для генерации общего кода на разные платформы - Android, IOs и Server. Описанные в одном месте общие классы и Http методы используются на разных платформах. Данный инструмент позволяет сократить время разработки в два раза. +Внутренний инструмент компании Touch Instinct для генерации общего кода на разные платформы - Android, iOS и Server. Описанные в одном месте общие классы и Http методы используются на разных платформах. Данный инструмент позволяет сократить время разработки в два раза. ### Работа с SharedPreferences -Чтобы сохранять простые данные в память смартфона, используются SharedPreferences. Модуль [storables](/storable) разработан для облегчения работы с SharedPreferences. +Чтобы сохранять простые данные в память смартфона, используются SharedPreferences. Модуль [storable](/storable) разработан для облегчения работы с SharedPreferences. ### Утилиты и extension функции В Roboswag также есть много [утилитарных](/utils) классов или [extension](/kotlin-extensions) функций, которые позволяют писать часто используемый код в одну строку. From 64b9dc19ae890e70aaf91e165385e28aea9d290d Mon Sep 17 00:00:00 2001 From: Maxim Bachinsky Date: Fri, 2 Aug 2019 16:59:54 +0300 Subject: [PATCH 15/17] little fix --- lifecycle-rx/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lifecycle-rx/README.md b/lifecycle-rx/README.md index c80e185..e527153 100644 --- a/lifecycle-rx/README.md +++ b/lifecycle-rx/README.md @@ -1,7 +1,7 @@ lifecycle-rx ===== -Модуль для преобразования событий из `Flowable`, `Observable`, `Single`, `Completable`, `Maybe` в `LiveData`. Нужен для передачи событий из `ViewModel` во `ViewController` с автоматическим управлением подписками во `ViewController`. +Модуль для преобразования событий из `Observable` в `LiveData`. Нужен для передачи событий из `ViewModel` во `ViewController` с автоматическим управлением подписками во `ViewController`. ### Основный интерфейсы и классы `Destroyable` - интерфейс, который содержит extansion-функцию *untilDestroy* для `Flowable`, `Observable`, `Single`, `Completable`, `Maybe`. Данная функция гарантирует, что подписка на события "умрет" после *onDestroy*. From 6c797c062235bd3e96c0ca580f67d58f194f9700 Mon Sep 17 00:00:00 2001 From: Maxim Bachinsky Date: Fri, 2 Aug 2019 17:00:27 +0300 Subject: [PATCH 16/17] replace or to and --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 13e655f..0130ec4 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ RecyclerView - один из самых часто используемых ин ### Работа с SharedPreferences Чтобы сохранять простые данные в память смартфона, используются SharedPreferences. Модуль [storable](/storable) разработан для облегчения работы с SharedPreferences. ### Утилиты и extension функции -В Roboswag также есть много [утилитарных](/utils) классов или [extension](/kotlin-extensions) функций, которые позволяют писать часто используемый код в одну строку. +В Roboswag также есть много [утилитарных](/utils) классов и [extension](/kotlin-extensions) функций, которые позволяют писать часто используемый код в одну строку. ### Подключение From 7b41318d70cc09e07400f56a1d3be095b17d3541 Mon Sep 17 00:00:00 2001 From: Maxim Bachinsky Date: Fri, 2 Aug 2019 17:08:22 +0300 Subject: [PATCH 17/17] comma fix --- navigation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/navigation/README.md b/navigation/README.md index 21b18bf..097ac0d 100644 --- a/navigation/README.md +++ b/navigation/README.md @@ -25,7 +25,7 @@ navigation `EmptyState` - пустое состояние. Использутся, когда при переходе к новому `ViewController` не нужно передавать никаких инициализирующих данных. -`LifecycleLoggingObserver` подписывается на вызовы методов жизненного цикла и логгирует номер строки из, которой был вызваны эти методы. +`LifecycleLoggingObserver` подписывается на вызовы методов жизненного цикла и логгирует номер строки, из которой был вызваны эти методы. Методы для навигации: