Skip to content

Commit

Permalink
Merge pull request #347 from novoda/gol/model-app-component
Browse files Browse the repository at this point in the history
GoL: MVP for App component
  • Loading branch information
tobiasheine authored Jan 10, 2018
2 parents eac0b1a + 688c821 commit 60c1d8c
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.novoda.gol

expect object Logger {

fun log(o: Any?)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.novoda.gol.presentation

import com.novoda.gol.patterns.PatternEntity
import kotlin.properties.Delegates.observable

class AppModel {

private var boardViewState by observable(BoardViewState(true)) { _, _, newValue ->
onBoardStateChanged(newValue)
}

var onSimulationStateChanged: (isIdle: Boolean) -> Unit by observable<(Boolean) -> Unit>({}) { _, _, newValue ->
newValue(boardViewState.isIdle)
}

var onBoardStateChanged: (BoardViewState) -> Unit by observable<(BoardViewState) -> Unit>({}) { _, _, newValue ->
newValue(boardViewState)
}

fun toggleSimulation() {
boardViewState = BoardViewState(isIdle = boardViewState.isIdle.not())
onSimulationStateChanged(boardViewState.isIdle)
}

fun selectPattern(pattern: PatternEntity) {
boardViewState = boardViewState.copy(selectedPattern = pattern)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.novoda.gol.presentation

class AppPresenter {

private val model = AppModel()

fun bind(view: AppView) {

model.onSimulationStateChanged = { isIdle ->
view.renderControlButtonLabel(if (isIdle) "Start simulation" else "Stop Simulation")
view.renderPatternSelectionVisibility(visibility = isIdle)
}

model.onBoardStateChanged = view::renderBoard

view.onControlButtonClicked = model::toggleSimulation

view.onPatternSelected = model::selectPattern
}

fun unbind(view: AppView) {
model.onSimulationStateChanged = {}
view.onControlButtonClicked = {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.novoda.gol.presentation

import com.novoda.gol.patterns.PatternEntity

interface AppView {

var onControlButtonClicked : () -> Unit
var onPatternSelected: (pattern : PatternEntity) -> Unit

fun renderControlButtonLabel(controlButtonLabel: String)
fun renderPatternSelectionVisibility(visibility: Boolean)
fun renderBoard(boardViewState: BoardViewState)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class BoardModelImpl private constructor(initialBoard: BoardEntity, private val
}

override fun selectPattern(pattern: PatternEntity) {
if (gameLoop.isLooping() || this.pattern == pattern) {
if (gameLoop.isLooping()) {
return
}
this.pattern = pattern
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.novoda.gol.presentation

import com.novoda.gol.patterns.PatternEntity

data class BoardViewState(
val isIdle: Boolean,
val selectedPattern: PatternEntity? = null
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.novoda.gol.presentation

import com.novoda.gol.patterns.PatternEntity

data class PatternViewState(
var shouldDisplay: Boolean,
val patternEntities: List<PatternEntity>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.novoda.gol

actual object Logger {

actual fun log(o: Any?) {
console.log(o)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,50 @@ package com.novoda.gol.components

import com.novoda.gol.patterns.PatternEntity
import com.novoda.gol.patterns.PatternRepository
import com.novoda.gol.presentation.AppPresenter
import com.novoda.gol.presentation.AppView
import com.novoda.gol.presentation.BoardViewState
import com.novoda.gol.presentation.PatternViewState
import kotlinx.html.style
import react.*
import react.dom.div
import react.dom.h2

class App : RComponent<RProps, State>() {
class App : RComponent<RProps, State>(), AppView {

override var onControlButtonClicked: () -> Unit = {}
override var onPatternSelected: (pattern: PatternEntity) -> Unit = {}

private val presenter: AppPresenter = AppPresenter()

override fun componentWillMount() {
presenter.bind(this)
}

override fun componentWillUnmount() {
presenter.unbind(this)
}

override fun State.init() {
patternEntities = PatternRepository.patterns()
isIdle = true
patternViewState = PatternViewState(true, PatternRepository.patterns())
}

override fun renderControlButtonLabel(controlButtonLabel: String) {
setState {
this.controlButtonLabel = controlButtonLabel
}
}

override fun renderPatternSelectionVisibility(visibility: Boolean) {
setState {
patternViewState.shouldDisplay = visibility
}
}

override fun renderBoard(boardViewState: BoardViewState) {
setState {
this.boardViewState = boardViewState
}
}

override fun RBuilder.render(): ReactElement? =
Expand All @@ -23,20 +57,18 @@ class App : RComponent<RProps, State>() {
flexDirection = "column"
}

controlButton(controlButtonLabel(), {
setState {
isIdle = isIdle.not()
}
controlButton(state.controlButtonLabel, {
onControlButtonClicked()
})

div {
attrs.style = kotlinext.js.js {
display = "flex"
}

board(state.isIdle, state.selectedPattern)
board(state.boardViewState)

if (state.isIdle) {
if (state.patternViewState.shouldDisplay) {

div {

Expand All @@ -46,26 +78,21 @@ class App : RComponent<RProps, State>() {

h2 { +"Choose a pattern" }

for (patternEntity in state.patternEntities) {
pattern(patternEntity, {
setState {
selectedPattern = patternEntity
}
state.patternViewState.patternEntities.forEach { pattern ->
pattern(pattern, {
onPatternSelected(pattern)
})
}
}
}
}
}

private fun controlButtonLabel() = if (state.isIdle) "Start simulation" else "Stop Simulation"

}

interface State : RState {
var patternEntities: List<PatternEntity>
var isIdle: Boolean
var selectedPattern: PatternEntity?
var patternViewState: PatternViewState
var boardViewState: BoardViewState
var controlButtonLabel: String
}

fun RBuilder.app() = child(App::class) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.novoda.gol.data.PositionEntity
import com.novoda.gol.patterns.PatternEntity
import com.novoda.gol.presentation.BoardPresenter
import com.novoda.gol.presentation.BoardView
import com.novoda.gol.presentation.BoardViewState
import kotlinext.js.js
import kotlinx.html.style
import react.*
Expand Down Expand Up @@ -39,18 +40,22 @@ class Board(boardProps: BoardProps) : RComponent<BoardProps, BoardState>(boardPr
override fun BoardState.init(props: BoardProps) {
presenter = BoardPresenter(50, 50)

if (props.selectedPattern != null) {
onPatternSelected.invoke(props.selectedPattern!!)
if (props.boardViewState.selectedPattern != null) {
onPatternSelected.invoke(props.boardViewState.selectedPattern!!)
}
}

override fun componentWillReceiveProps(nextProps: BoardProps) {
if (nextProps.isIdle.not()) {
val state = nextProps.boardViewState

if (state.isIdle.not()) {
onStartSimulationClicked()
} else {
onStopSimulationClicked()
}
onPatternSelected.invoke(nextProps.selectedPattern!!)
if (state.selectedPattern != null) {
onPatternSelected.invoke(state.selectedPattern!!)
}
}

override fun RBuilder.render() = renderBoard(state)
Expand All @@ -74,16 +79,12 @@ class Board(boardProps: BoardProps) : RComponent<BoardProps, BoardState>(boardPr
}
}

data class BoardProps(var isIdle: Boolean, var selectedPattern: PatternEntity? = null) : RProps
data class BoardProps(var boardViewState: BoardViewState) : RProps

interface BoardState : RState {
var boardEntity: BoardEntity
}

fun RBuilder.board(isIdle: Boolean, selectedPattern: PatternEntity? = null) = child(
Board::class) {
attrs.isIdle = isIdle
attrs.selectedPattern = selectedPattern
fun RBuilder.board(board: BoardViewState) = child(Board::class) {
attrs.boardViewState = board
}


Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ fun RBuilder.pattern(patternEntity: PatternEntity, onPatternSelected: () -> Unit
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.novoda.gol

actual object Logger {

actual fun log(o: Any?) {
System.out.println(o)
}

}

0 comments on commit 60c1d8c

Please sign in to comment.