From b18eb71559a1fc2db628a96fee02ba1e81073559 Mon Sep 17 00:00:00 2001 From: Joffrey Bion Date: Wed, 1 Jul 2020 02:47:48 +0200 Subject: Use correct keys in player list to allow animations on reorder --- .../sevenwonders/ui/components/lobby/RadialList.kt | 37 +++++++++------- .../ui/components/lobby/RadialPlayerList.kt | 50 ++++++++++++++-------- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialList.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialList.kt index 10ddb2b1..e27e1cd8 100644 --- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialList.kt +++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialList.kt @@ -9,11 +9,11 @@ import react.ReactElement import react.dom.* import styled.* -typealias ElementBuilder = RBuilder.() -> ReactElement - -fun RBuilder.radialList( - itemBuilders: List, - centerElementBuilder: ElementBuilder, +fun RBuilder.radialList( + items: List, + centerElement: ReactElement, + renderItem: (T) -> ReactElement, + getKey: (T) -> String, itemWidth: Int, itemHeight: Int, options: RadialConfig = RadialConfig(), @@ -30,13 +30,18 @@ fun RBuilder.radialList( height = containerHeight.px } block() - radialListItems(itemBuilders, options) - radialListCenter(centerElementBuilder) + radialListItems(items, renderItem, getKey, options) + radialListCenter(centerElement) } } -private fun RBuilder.radialListItems(itemBuilders: List, radialConfig: RadialConfig): ReactElement { - val offsets = offsetsFromCenter(itemBuilders.size, radialConfig) +private fun RBuilder.radialListItems( + items: List, + renderItem: (T) -> ReactElement, + getKey: (T) -> String, + radialConfig: RadialConfig +): ReactElement { + val offsets = offsetsFromCenter(items.size, radialConfig) return styledUl { css { zeroMargins() @@ -46,13 +51,13 @@ private fun RBuilder.radialListItems(itemBuilders: List, radialC height = radialConfig.diameter.px absoluteCenter() } - itemBuilders.forEachIndexed { i, itemBuilder -> - radialListItem(itemBuilder, i, offsets[i]) + items.forEachIndexed { i, item -> + radialListItem(renderItem(item), getKey(item), offsets[i]) } } } -private fun RBuilder.radialListItem(itemBuilder: ElementBuilder, i: Int, offset: CartesianCoords): ReactElement { +private fun RBuilder.radialListItem(item: ReactElement, key: String, offset: CartesianCoords): ReactElement { return styledLi { css { display = Display.block @@ -69,13 +74,13 @@ private fun RBuilder.radialListItem(itemBuilder: ElementBuilder, i: Int, offset: } } attrs { - key = "$i" + this.key = key } - itemBuilder() + child(item) } } -private fun RBuilder.radialListCenter(centerElement: ElementBuilder?): ReactElement? { +private fun RBuilder.radialListCenter(centerElement: ReactElement?): ReactElement? { if (centerElement == null) { return null } @@ -84,7 +89,7 @@ private fun RBuilder.radialListCenter(centerElement: ElementBuilder?): ReactElem zIndex = 0 absoluteCenter() } - centerElement() + child(centerElement) } } diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt index 78133f92..061d680f 100644 --- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt +++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt @@ -5,24 +5,35 @@ import com.palantir.blueprintjs.bpIcon import kotlinx.css.* import org.luxons.sevenwonders.model.api.PlayerDTO import org.luxons.sevenwonders.model.api.actions.Icon -import react.RBuilder -import react.ReactElement +import react.* import react.dom.* import styled.css import styled.styledDiv import styled.styledH4 +private sealed class PlayerItem { + abstract val username: String + + data class Player(val player: PlayerDTO) : PlayerItem() { + override val username = player.username + } + data class Placeholder(val index: Int) : PlayerItem() { + override val username = "player-placeholder-$index" + } +} + fun RBuilder.radialPlayerList(players: List, currentPlayer: PlayerDTO): ReactElement { - val playerItemBuilders = players - .growTo(targetSize = 3) + val playerItems = players + .growWithPlaceholders(targetSize = 3) .withUserFirst(currentPlayer) - .map { p -> p.elementBuilder(p?.username == currentPlayer.username) } - val tableImgBuilder: ElementBuilder = { roundTableImg() } + val tableImg = buildElement { roundTableImg() } return radialList( - itemBuilders = playerItemBuilders, - centerElementBuilder = tableImgBuilder, + items = playerItems, + centerElement = tableImg, + renderItem = { it.renderAsListItem(it.username == currentPlayer.username) }, + getKey = { it.username }, itemWidth = 120, itemHeight = 100, options = RadialConfig( @@ -40,25 +51,26 @@ private fun RBuilder.roundTableImg(): ReactElement = img(src = "images/round-tab } } -private fun List.withUserFirst(me: PlayerDTO): List { - val nonUsersBeginning = takeWhile { it?.username != me.username } +private fun List.withUserFirst(me: PlayerDTO): List { + val nonUsersBeginning = takeWhile { (it as? PlayerItem.Player)?.player?.username != me.username } val userToEnd = subList(nonUsersBeginning.size, size) return userToEnd + nonUsersBeginning } -private fun List.growTo(targetSize: Int): List { - if (size >= targetSize) return this - return this + List(targetSize - size) { null } -} - -private fun PlayerDTO?.elementBuilder(isMe: Boolean): ElementBuilder { - if (this == null) { - return { playerPlaceholder() } +private fun List.growWithPlaceholders(targetSize: Int): List { + val items = map { PlayerItem.Player(it) } + return if (size >= targetSize) { + items } else { - return { playerItem(this@elementBuilder, isMe) } + items + List(targetSize - size) { PlayerItem.Placeholder(size + it) } } } +private fun PlayerItem.renderAsListItem(isMe: Boolean): ReactElement = when (this) { + is PlayerItem.Placeholder -> buildElement { playerPlaceholder() } + is PlayerItem.Player -> buildElement { playerItem(this@renderAsListItem.player, isMe) } +} + private fun RBuilder.playerItem(player: PlayerDTO, isMe: Boolean): ReactElement = styledDiv { css { display = Display.flex -- cgit