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
8 changes: 7 additions & 1 deletion learning/legacy/moko-kswift.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
sidebar_position: 7
---

# moko-kswift
# moko-kswift (legacy)

:::caution

Плагин **moko-kswift** больше не используется в новых проектах. Вместо него применяется **SKIE** — см. [статью про SKIE](../../learning/kotlin-multiplatform/mobile-highlights#skie--swift-friendly-api-из-коробки).

:::

Плагин устарел, используйте [https://skie.touchlab.co](https://skie.touchlab.co)

Expand Down
7 changes: 7 additions & 0 deletions learning/legacy/state.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ viewModel.state.observe(viewLifecycleOwner) { state ->
Теперь, для каждого элемента на основе значения стейта мы устанавливаем значение всего один раз, в одном единственном месте. Отлаживать и изменять такой код будет гораздо легче.

### Обработка на iOS

:::caution

Раздел описывает устаревший подход с **moko-kswift** и UIKit. В актуальных проектах используется **SKIE** для Swift-friendly API и SwiftUI для UI. Подробнее — в [статье про SKIE](../../learning/kotlin-multiplatform/mobile-highlights#skie--swift-friendly-api-из-коробки).

:::

#### moko-kswift

За счет [moko-kswift](/learning/legacy/moko-kswift) у нас есть возможность использовать `sealed interface` для `State` и `Actions` из общего кода в виде `enum` в Swift, чтобы можно было обрабатывать объекты в `switch` без ветки `default`.
Expand Down
2 changes: 1 addition & 1 deletion onboarding/moko.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ MOKO — это наши мультиплатформенные open-source би
Изучите библиотеку [MOKO resources](https://kmm.icerock.dev/university/icerock-basics/resources-in-common#библиотека-moko-resources), [дополнение](../learning/libraries/moko/moko-resources).

Также ознакомьтесь с:
- использованием классов-оберток [CFlow и CStateFlow](https://kmm.icerock.dev/university/icerock-basics/mvvm#flow-c-moko-kswift) из [MOKO MVVM](../learning/libraries/moko/moko-mvvm)
- использованием классов-оберток [CFlow и CStateFlow](https://kmm.icerock.dev/university/icerock-basics/mvvm) из [MOKO MVVM](../learning/libraries/moko/moko-mvvm)
- использованием [mvvm-state](https://kmm.icerock.dev/university/lists/moko-paging#moko-mvvm-state) из MOKO MVVM
- зачем нужна библиотека [МОКО Network](https://kmm.icerock.dev/learning/libraries/moko/moko-network)
- видео [о MOKO paging](https://kmm.icerock.dev/learning/libraries/moko/moko-paging), конкретные примеры текущего применения стоит смотреть в текущих проектах.
399 changes: 147 additions & 252 deletions university/4-icerock-basics/mvvm.md

Large diffs are not rendered by default.

149 changes: 97 additions & 52 deletions university/4-icerock-basics/practice.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ sidebar_position: 15
21. Локализовать проект используя `sheets-localizations-generator`
- обеспечьте поддержку русского и английского языков
22. Обеспечить поддержку iOS 13.0
23. UI на Android реализовать на Jetpack Compose, на iOS — на SwiftUI

## Классы приложения

Expand Down Expand Up @@ -85,24 +86,28 @@ class KeyValueStorage {

### mpp-library-feature-auth
```kotlin
class AuthViewModel {
val token: MutableStateFlow<String>
val state: StateFlow<State>
val actions: Flow<Action>
class AuthViewModel(
private val repository: AppRepository,
) : ViewModel() {
val token: CMutableStateFlow<String> = MutableStateFlow("").cMutableStateFlow()
val state: CStateFlow<State> // TODO: инициализация с начальным состоянием

private val _actions: Channel<Actions> = Channel()
val actions: CFlow<Actions> = _actions.receiveAsFlow().cFlow()

fun onSignButtonPressed() {
// TODO:
}

sealed interface State {
object Idle : State
object Loading : State
data class InvalidInput(val reason: String) : State
data object Idle : State
data object Loading : State
data class InvalidInput(val reason: StringDesc) : State
}

sealed interface Action {
data class ShowError(val message: String) : Action
object RouteToMain : Action
sealed interface Actions {
data class ShowError(val message: StringDesc) : Actions
data object RouteToMain : Actions
}

// TODO:
Expand All @@ -111,12 +116,14 @@ class AuthViewModel {

### mpp-library-feature-repo
```kotlin
class RepositoryInfoViewModel {
val state: StateFlow<State>
class RepositoryInfoViewModel(
private val repository: AppRepository,
) : ViewModel() {
val state: CStateFlow<State> // TODO: инициализация

sealed interface State {
object Loading : State
data class Error(val error: String) : State
data object Loading : State
data class Error(val error: StringDesc) : State

data class Loaded(
val githubRepo: Repo,
Expand All @@ -125,23 +132,25 @@ class RepositoryInfoViewModel {
}

sealed interface ReadmeState {
object Loading : ReadmeState
object Empty : ReadmeState
data class Error(val error: String) : ReadmeState
data object Loading : ReadmeState
data object Empty : ReadmeState
data class Error(val error: StringDesc) : ReadmeState
data class Loaded(val markdown: String) : ReadmeState
}

// TODO:
}

class RepositoriesListViewModel {
val state: StateFlow<State>
class RepositoriesListViewModel(
private val repository: AppRepository,
) : ViewModel() {
val state: CStateFlow<State> // TODO: инициализация

sealed interface State {
object Loading : State
data object Loading : State
data class Loaded(val repos: List<Repo>) : State
data class Error(val error: String) : State
object Empty : State
data class Error(val error: StringDesc) : State
data object Empty : State
}

// TODO:
Expand All @@ -150,35 +159,71 @@ class RepositoriesListViewModel {

### android-app
```kotlin
class MainActivity: AppCompatActivity {
// TODO:
@AndroidEntryPoint
class MainActivity : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppNavHost()
}
}
}

class AuthFragment: Fragment {
// TODO:
@Composable
fun AuthScreen(
viewModel: AuthViewModel = koinViewModel()
) {
// TODO: экран авторизации
}

class RepositoriesListFragment: Fragment {
// TODO:
@Composable
fun RepositoriesListScreen(
viewModel: RepositoriesListViewModel = koinViewModel()
) {
// TODO: список репозиториев
}

class DetailInfoFragment: Fragment {
// TODO:
@Composable
fun DetailInfoScreen(
viewModel: RepositoryInfoViewModel = koinViewModel()
) {
// TODO: детальная информация о репозитории
}
```

### ios-app
```swift
class RepositoriesListViewController: UIViewController {
// TODO:
@main
struct MobileApp: App {
var body: some Scene {
WindowGroup {
AuthView()
}
}
}

class RepositoryDetailInfoViewController: UIViewController {
// TODO:
struct AuthView: View {
@ViewModelWrapper private var viewModel: AuthViewModel = Koin.instance.getAuthViewModel(params: ...)

var body: some View {
// TODO: экран авторизации
}
}

class AuthViewController: UIViewController {
// TODO:
struct RepositoriesListView: View {
@ViewModelWrapper private var viewModel: RepositoriesListViewModel = Koin.instance.getRepositoriesListViewModel()

var body: some View {
// TODO: список репозиториев
}
}

struct DetailInfoView: View {
@ViewModelWrapper private var viewModel: RepositoryInfoViewModel = Koin.instance.getRepositoryInfoViewModel(params: ...)

var body: some View {
// TODO: детальная информация о репозитории
}
}
```

Expand All @@ -199,27 +244,27 @@ class GitHubRepoRepository:::common
class KeyValueStorage:::common

class MainActivity:::android
class RepositoriesListFragment:::android
class DetailInfoFragment:::android
class AuthFragment:::android
class RepositoriesListViewController:::ios
class RepositoryDetailInfoViewController:::ios
class AuthViewController:::ios

MainActivity --> AuthFragment
MainActivity --> RepositoriesListFragment
MainActivity --> DetailInfoFragment
RepositoriesListFragment --> RepositoriesListViewModel
DetailInfoFragment --> RepositoryInfoViewModel
AuthFragment --> AuthViewModel
class AuthScreen:::android
class RepositoriesListScreen:::android
class DetailInfoScreen:::android
class AuthView:::ios
class RepositoriesListView:::ios
class DetailInfoView:::ios

MainActivity --> AuthScreen
MainActivity --> RepositoriesListScreen
MainActivity --> DetailInfoScreen
AuthScreen --> AuthViewModel
RepositoriesListScreen --> RepositoriesListViewModel
DetailInfoScreen --> RepositoryInfoViewModel

RepositoriesListViewModel --> GitHubRepoRepository
AuthViewModel --> GitHubRepoRepository
RepositoryInfoViewModel --> GitHubRepoRepository

RepositoriesListViewController --> RepositoriesListViewModel
RepositoryDetailInfoViewController --> RepositoryInfoViewModel
AuthViewController --> AuthViewModel
AuthView --> AuthViewModel
RepositoriesListView --> RepositoriesListViewModel
DetailInfoView --> RepositoryInfoViewModel
GitHubRepoRepository --> KeyValueStorage
```

Expand Down
Loading
Loading