|
// AppVM |
|
// --------------------------------------------------------------------------------------------------------------------- |
|
|
|
public object AppContract { |
|
public data class State( |
|
val selectedFile: String? = null |
|
) |
|
public sealed class Inputs { |
|
public data class SetSelectedFile(val selectedFile: String) : Inputs() |
|
public object CloseSelectedFile : Inputs() |
|
} |
|
public sealed class Events { |
|
|
|
} |
|
} |
|
|
|
public class AppInputHandler : InputHandler<AppContract.Inputs, AppContract.Events, AppContract.State> { |
|
override suspend fun InputHandlerScope<AppContract.Inputs, AppContract.Events, AppContract.State>.handleInput( |
|
input: AppContract.Inputs |
|
): Unit = when(input) { |
|
is AppContract.Inputs.SetSelectedFile -> { |
|
updateState { it.copy(selectedFile = input.selectedFile) } |
|
} |
|
is AppContract.Inputs.CloseSelectedFile -> { |
|
updateState { it.copy(selectedFile = null) } |
|
} |
|
} |
|
} |
|
|
|
public fun getAppViewModel(coroutineScope: CoroutineScope): BallastViewModel<AppContract.Inputs, AppContract.Events, AppContract.State> { |
|
TODO() |
|
} |
|
|
|
// ListVM |
|
// --------------------------------------------------------------------------------------------------------------------- |
|
|
|
public object ListContract { |
|
public data class State( |
|
val selectedFile: String? = null, |
|
val allFiles: List<String> = emptyList(), |
|
) |
|
public sealed class Inputs { |
|
public object Initialize: Inputs() |
|
public data class AppStateUpdated(val appState: AppContract.State) : Inputs() |
|
|
|
public data class FilesListUpdated(val files: List<String>) : Inputs() |
|
public data class OpenFile(val file: String) : Inputs() |
|
public data class CreateFile(val fileName: String) : Inputs() |
|
public data class DeleteFile(val file: String) : Inputs() |
|
} |
|
public sealed class Events { } |
|
} |
|
|
|
public class ListInputHandler( |
|
private val appViewModel: BallastViewModel<AppContract.Inputs, AppContract.Events, AppContract.State> |
|
) : InputHandler<ListContract.Inputs, ListContract.Events, ListContract.State> { |
|
override suspend fun InputHandlerScope<ListContract.Inputs, ListContract.Events, ListContract.State>.handleInput( |
|
input: ListContract.Inputs |
|
): Unit = when(input) { |
|
is ListContract.Inputs.Initialize -> { |
|
observeFlows( |
|
"AppStateUpdated", |
|
appViewModel.observeStates().map { ListContract.Inputs.AppStateUpdated(it) }m |
|
) |
|
} |
|
is ListContract.Inputs.AppStateUpdated -> { |
|
updateState { it.copy(selectedFile = input.appState.selectedFile) } |
|
} |
|
|
|
is ListContract.Inputs.FilesListUpdated -> { |
|
updateState { it.copy(allFiles = input.files) } |
|
} |
|
is ListContract.Inputs.OpenFile -> { |
|
sideJob("OpenFile") { |
|
appViewModel.send(AppContract.Inputs.SetSelectedFile(input.file)) |
|
} |
|
} |
|
is ListContract.Inputs.CreateFile -> TODO() |
|
is ListContract.Inputs.DeleteFile -> TODO() |
|
} |
|
} |
|
|
|
public fun getListViewModel(coroutineScope: CoroutineScope, appViewModel: BallastViewModel<AppContract.Inputs, AppContract.Events, AppContract.State>): BallastViewModel<ListContract.Inputs, ListContract.Events, ListContract.State> { |
|
TODO() |
|
} |
|
|
|
// EditorVM |
|
// --------------------------------------------------------------------------------------------------------------------- |
|
|
|
public object EditorContract { |
|
public data class State( |
|
val selectedFile: String? = null |
|
) |
|
public sealed class Inputs { |
|
public object Initialize: Inputs() |
|
public data class AppStateUpdated(val appState: AppContract.State) : Inputs() |
|
public object CloseFile : Inputs() |
|
} |
|
public sealed class Events { } |
|
} |
|
|
|
public class EditorInputHandler( |
|
private val appViewModel: BallastViewModel<AppContract.Inputs, AppContract.Events, AppContract.State> |
|
) : InputHandler<EditorContract.Inputs, EditorContract.Events, EditorContract.State> { |
|
override suspend fun InputHandlerScope<EditorContract.Inputs, EditorContract.Events, EditorContract.State>.handleInput( |
|
input: EditorContract.Inputs |
|
): Unit = when(input) { |
|
is EditorContract.Inputs.Initialize -> { |
|
observeFlows("AppStateUpdated", appViewModel.observeStates().map { EditorContract.Inputs.AppStateUpdated(it) }) |
|
} |
|
is EditorContract.Inputs.AppStateUpdated -> { |
|
updateState { it.copy(selectedFile = input.appState.selectedFile) } |
|
} |
|
is EditorContract.Inputs.CloseFile -> { |
|
sideJob("CloseFile") { |
|
appViewModel.send(AppContract.Inputs.CloseSelectedFile) |
|
} |
|
} |
|
} |
|
} |
|
|
|
public fun getEditorViewModel(coroutineScope: CoroutineScope): BallastViewModel<EditorContract.Inputs, EditorContract.Events, EditorContract.State> { |
|
TODO() |
|
} |
|
|
|
// Compose UI |
|
// --------------------------------------------------------------------------------------------------------------------- |
|
|
|
@Composable |
|
public fun App() { |
|
val appCoroutineScope = rememberCoroutineScope() |
|
val appVm = remember(appCoroutineScope) { getAppViewModel(appCoroutineScope) } |
|
|
|
Row { |
|
Column { |
|
ListView(appVm) |
|
} |
|
Column { |
|
EditorView(appVm) |
|
} |
|
} |
|
} |
|
|
|
@Composable |
|
public fun ListView(appViewModel: BallastViewModel<AppContract.Inputs, AppContract.Events, AppContract.State>) { |
|
val listCoroutineScope = rememberCoroutineScope() |
|
val listVm = remember(listCoroutineScope, appViewModel) { getListViewModel(listCoroutineScope, appViewModel) } |
|
val listVmState by listVm.observeStates().collectAsState() |
|
// display files list |
|
} |
|
|
|
@Composable |
|
public fun EditorView(appViewModel: BallastViewModel<AppContract.Inputs, AppContract.Events, AppContract.State>) { |
|
val editorCoroutineScope = rememberCoroutineScope() |
|
val editorVm = remember(editorCoroutineScope, appViewModel) { getEditorViewModel(editorCoroutineScope, appViewModel) } |
|
val editorVmState by editorVm.observeStates().collectAsState() |
|
// display selected file in the editor |
|
} |