diff --git a/learning/code-style/functions-references-instead-of-lambdas.md b/learning/code-style/functions-references-instead-of-lambdas.md index 138fecef2..edc7a9d6d 100644 --- a/learning/code-style/functions-references-instead-of-lambdas.md +++ b/learning/code-style/functions-references-instead-of-lambdas.md @@ -12,21 +12,21 @@ sidebar_position: 6 println(it) } - val upperCaseNames = nameList.map { - it.toUpperCase() - } - - objectsList.asSequence() - .filter { it.isOnline() } - .map { handleAndTransform(it) } - .toList() - ``` + val upperCaseNames = nameList.map { + it.uppercase() + } + + objectsList.asSequence() + .filter { it.isOnline() } + .map { handleAndTransform(it) } + .toList() + ``` **Как лучше сделать:** ```kotlin - nameList.forEach(::println) - - val upperCaseNames = nameList.map(String::toUpperCase) + nameList.forEach(::println) + + val upperCaseNames = nameList.map(String::uppercase) objectsList.asSequence() .filter(Any::isOnline) @@ -46,20 +46,16 @@ sidebar_position: 6 chatController.loadPage(offset, pageSize) }, comparator = MessageComparator(), - nextPageListener = { result -> - if (result.isFailure) { - eventsDispatcher.dispatchEvent { - showToastMessage(errorsMapper(result.exceptionOrNull())) - } - } - }, - refreshListener = { result -> - if (result.isFailure) { - eventsDispatcher.dispatchEvent { - showToastMessage(errorsMapper(result.exceptionOrNull())) - } - } - }, + nextPageListener = { result -> + if (result.isFailure) { + showToastMessage(errorsMapper(result.exceptionOrNull())) + } + }, + refreshListener = { result -> + if (result.isFailure) { + showToastMessage(errorsMapper(result.exceptionOrNull())) + } + }, initValue = listOf() ) ``` @@ -79,18 +75,14 @@ sidebar_position: 6 ) private fun onListNextPageLoadFinished(result: Result>) { - if (result.isFailure) { - eventsDispatcher.dispatchEvent { - showToastMessage(errorsMapper(result.exceptionOrNull())) - } - } - } - - private fun onListRefreshFinished(result: Result>) { - if (result.isFailure) { - eventsDispatcher.dispatchEvent { - showToastMessage(errorsMapper(result.exceptionOrNull())) - } - } - } + if (result.isFailure) { + showToastMessage(errorsMapper(result.exceptionOrNull())) + } + } + + private fun onListRefreshFinished(result: Result>) { + if (result.isFailure) { + showToastMessage(errorsMapper(result.exceptionOrNull())) + } + } ``` diff --git a/learning/code-style/general-rules.md b/learning/code-style/general-rules.md index 3e77f6186..f4fb21b0a 100644 --- a/learning/code-style/general-rules.md +++ b/learning/code-style/general-rules.md @@ -11,7 +11,7 @@ sidebar_position: 0 - [Избегайте избыточных конструкций](https://kotlinlang.org/docs/coding-conventions.html#avoiding-redundant-constructs) - [Идиоматичное применение Kotlin](https://kotlinlang.org/docs/coding-conventions.html#idiomatic-use-of-language-features) -2. Содержимое класса должно быть расположенно в [следующем порядке](https://kotlinlang.org/docs/coding-conventions.html#class-layout): +2. Содержимое класса должно быть расположено в [следующем порядке](https://kotlinlang.org/docs/coding-conventions.html#class-layout): - Объявление свойств и блока инициализации - Второстепенные конструкторы - Объявление методов в порядке сокращения видимости @@ -25,13 +25,22 @@ sidebar_position: 0 3. Без необходимости не используйте вложенные классы и интерфейсы: - Внутренние ([Inner](https://kotlinlang.org/docs/nested-classes.html)) классы имеет смысл делать только когда в нем необходима ссылка на объект внешнего класса. Такие классы отдельно требуют модификатор **inner** - - Вложенные ([Nested](https://kotlinlang.org/docs/nested-classes.html)) классы имеет смысл делать только если он логически зависим от внешнего класса и необходимо ограничить видимость (**scope**) такого вложенного класса/интерфейса. Например, интерфейс слушателя событий **EventsListener** логично делать вложенным в класс конкретной вью-модели, реализующей интерфейс [EventsDispatcherOwner](https://github.com/icerockdev/moko-mvvm/blob/master/mvvm-core/src/commonMain/kotlin/dev/icerock/moko/mvvm/dispatcher/EventsDispatcherOwner.kt) для слушателя **EventsListener**. Потому что объекты интерфейса **EventsListener** используются только внутри вью-модели и вне этой конкретной вью-модели такой интерфейс не имеет смысла и нигде использоваться не будет. + - Вложенные ([Nested](https://kotlinlang.org/docs/nested-classes.html)) классы имеет смысл делать только если он логически зависим от внешнего класса и необходимо ограничить видимость (**scope**) такого вложенного класса/интерфейса. Например, `sealed interface Actions` логично делать вложенным в класс конкретной ViewModel, потому что эти Actions имеют смысл только внутри этой ViewModel и нигде больше не используются: + + ```kotlin + class AuthViewModel : ViewModel() { + sealed interface Actions { + data object RouteToMain : Actions + data class ShowMessage(val message: StringDesc) : Actions + } + } + ``` 4. Выносите утилитарный код в функции верхнего уровня в отдельный файл без создания дополнительных классов или объектов. 5. Настройте в Android Studio официальный стиль кода для Kotlin, чтобы корректно срабатывало автоматическое форматирование кода ([сочетание клавиш для клавиатуры](https://stackoverflow.com/questions/16580171/code-formatting-shortcuts-in-android-studio-for-operation-systems/16580200#16580200)). Отключите сокращение импортов через звезду **import ***. - Помимо включения **Use single name import** важно не упустить пакеты-исключения - они перечислены ниже в разделе **Packages to Use import with *** - оттуда тоже нужно удалить все, кроме котлин синтетиков, но мы их не используем. + Помимо включения **Use single name import** важно не упустить пакеты-исключения — они перечислены ниже в разделе **Packages to Use import with *** — оттуда тоже нужно удалить все. ![img.png](media/imports-setup.png) 6. Настройте форматирование кода, отключите галочку, чтобы не добавлялась лишняя запятая diff --git a/learning/code-style/media/turn-off-trailing-comma.png b/learning/code-style/media/turn-off-trailing-comma.png deleted file mode 100644 index 18850106b..000000000 Binary files a/learning/code-style/media/turn-off-trailing-comma.png and /dev/null differ diff --git a/learning/code-style/property-name.md b/learning/code-style/property-name.md index 96db8fadc..e939c620c 100644 --- a/learning/code-style/property-name.md +++ b/learning/code-style/property-name.md @@ -20,8 +20,8 @@ sidebar_position: 1 var threadsCounter = 0 ``` -1. Для названий свойств с булевым типом (или для **LiveData(Boolean)**) имеет смысл добавлять префикс **is**: +1. Для названий свойств с булевым типом (или для **StateFlow(Boolean)**) имеет смысл добавлять префикс **is**: ```kotlin - val isLoading: LiveData = _isLoading.readOnly() + val isLoading: StateFlow = _isLoading.asStateFlow() val isButtonEnabled = false ``` diff --git a/learning/code-style/property-type.md b/learning/code-style/property-type.md index 06a18a715..b5c9e52a7 100644 --- a/learning/code-style/property-type.md +++ b/learning/code-style/property-type.md @@ -13,7 +13,8 @@ sidebar_position: 3 **Как лучше сделать:** ```kotlin - val isFollowed: LiveData = followRepository.isFollow(participantOrTeamId) + val isFollowed: StateFlow = followRepository.isFollow(participantOrTeamId) + .stateIn(viewModelScope, SharingStarted.Eagerly, false) ``` 1. Имеет смысл явно указывать тип при объявлении переменной внутри функций и методов, которой присваивается результат крупного выражения: diff --git a/learning/code-style/separate-by-files.md b/learning/code-style/separate-by-files.md index 44bef566b..0571af578 100644 --- a/learning/code-style/separate-by-files.md +++ b/learning/code-style/separate-by-files.md @@ -4,7 +4,7 @@ sidebar_position: 7 # Разделение по файлам -1. Классы/интерфейсы/объекты располагаются в своем файле (два класса в одном файле не приветствуется). В файле рядом с основным объявлением (класс/интерфейс/объект) могут находиться различные **extension** методы, относящиеся к этому классу. Например в файл класса сущности доменного уровня ещё объявляется экстеншен маппинга сетевой сущности в доменную: +1. Классы/интерфейсы/объекты располагаются в своем файле (два класса в одном файле не приветствуется). В файле рядом с основным объявлением (класс/интерфейс/объект) могут находиться различные **extension** методы, относящиеся к этому классу. Например, в файле класса доменной сущности может объявляться extension для маппинга из сетевой сущности: Например: ```kotlin