Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 32 additions & 40 deletions learning/code-style/functions-references-instead-of-lambdas.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
)
```
Expand All @@ -79,18 +75,14 @@ sidebar_position: 6
)

private fun onListNextPageLoadFinished(result: Result<List<ChatMessage>>) {
if (result.isFailure) {
eventsDispatcher.dispatchEvent {
showToastMessage(errorsMapper(result.exceptionOrNull()))
}
}
}

private fun onListRefreshFinished(result: Result<List<ChatMessage>>) {
if (result.isFailure) {
eventsDispatcher.dispatchEvent {
showToastMessage(errorsMapper(result.exceptionOrNull()))
}
}
}
if (result.isFailure) {
showToastMessage(errorsMapper(result.exceptionOrNull()))
}
}

private fun onListRefreshFinished(result: Result<List<ChatMessage>>) {
if (result.isFailure) {
showToastMessage(errorsMapper(result.exceptionOrNull()))
}
}
```
15 changes: 12 additions & 3 deletions learning/code-style/general-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -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):
- Объявление свойств и блока инициализации
- Второстепенные конструкторы
- Объявление методов в порядке сокращения видимости
Expand All @@ -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. Настройте форматирование кода, отключите галочку, чтобы не добавлялась лишняя запятая
Expand Down
Binary file not shown.
4 changes: 2 additions & 2 deletions learning/code-style/property-name.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ sidebar_position: 1
var threadsCounter = 0
```

1. Для названий свойств с булевым типом (или для **LiveData(Boolean)**) имеет смысл добавлять префикс **is**:
1. Для названий свойств с булевым типом (или для **StateFlow(Boolean)**) имеет смысл добавлять префикс **is**:
```kotlin
val isLoading: LiveData<Boolean> = _isLoading.readOnly()
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
val isButtonEnabled = false
```
3 changes: 2 additions & 1 deletion learning/code-style/property-type.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ sidebar_position: 3

**Как лучше сделать:**
```kotlin
val isFollowed: LiveData<Boolean> = followRepository.isFollow(participantOrTeamId)
val isFollowed: StateFlow<Boolean> = followRepository.isFollow(participantOrTeamId)
.stateIn(viewModelScope, SharingStarted.Eagerly, false)
```

1. Имеет смысл явно указывать тип при объявлении переменной внутри функций и методов, которой присваивается результат крупного выражения:
Expand Down
2 changes: 1 addition & 1 deletion learning/code-style/separate-by-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ sidebar_position: 7

# Разделение по файлам

1. Классы/интерфейсы/объекты располагаются в своем файле (два класса в одном файле не приветствуется). В файле рядом с основным объявлением (класс/интерфейс/объект) могут находиться различные **extension** методы, относящиеся к этому классу. Например в файл класса сущности доменного уровня ещё объявляется экстеншен маппинга сетевой сущности в доменную:
1. Классы/интерфейсы/объекты располагаются в своем файле (два класса в одном файле не приветствуется). В файле рядом с основным объявлением (класс/интерфейс/объект) могут находиться различные **extension** методы, относящиеся к этому классу. Например, в файле класса доменной сущности может объявляться extension для маппинга из сетевой сущности:

Например:
```kotlin
Expand Down
Loading