Skip to content

Commit

Permalink
Merge branch 'main' into minor-improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
mmartosdev committed Oct 5, 2023
2 parents 6a6934a + 65fe269 commit aaacb91
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import kotlin.math.min
import kotlin.random.Random

class GridPuzzleVisualisation(
private val uiContext: UiContext,
uiContext: UiContext,
defaultAnimationSpec: SpringSpec<Float>
) : BaseMotionController<PuzzlePiece, State, MutableUiState, TargetUiState>(
uiContext = uiContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ class Assemble(
override var mode: Operation.Mode
) : BaseOperation<State>() {

override fun isApplicable(state: GridPuzzleModel.State): Boolean =
override fun isApplicable(state: State): Boolean =
true

override fun createFromState(baseLineState: GridPuzzleModel.State): GridPuzzleModel.State =
override fun createFromState(baseLineState: State): State =
baseLineState

override fun createTargetState(fromState: GridPuzzleModel.State): GridPuzzleModel.State =
override fun createTargetState(fromState: State): State =
fromState.copy(
puzzleMode = GridPuzzleModel.PuzzleMode.ASSEMBLED
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ class Carousel(
override var mode: Operation.Mode
) : BaseOperation<State>() {

override fun isApplicable(state: GridPuzzleModel.State): Boolean =
override fun isApplicable(state: State): Boolean =
true

override fun createFromState(baseLineState: GridPuzzleModel.State): GridPuzzleModel.State =
override fun createFromState(baseLineState: State): State =
baseLineState

override fun createTargetState(fromState: GridPuzzleModel.State): GridPuzzleModel.State =
override fun createTargetState(fromState: State): State =
fromState.copy(
puzzleMode = GridPuzzleModel.PuzzleMode.CAROUSEL
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ class Flip(
override var mode: Operation.Mode
) : BaseOperation<State>() {

override fun isApplicable(state: GridPuzzleModel.State): Boolean =
override fun isApplicable(state: State): Boolean =
true

override fun createFromState(baseLineState: GridPuzzleModel.State): GridPuzzleModel.State =
override fun createFromState(baseLineState: State): State =
baseLineState

override fun createTargetState(fromState: GridPuzzleModel.State): GridPuzzleModel.State =
override fun createTargetState(fromState: State): State =
fromState.copy(
puzzleMode = GridPuzzleModel.PuzzleMode.FLIPPED
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ class Scatter(
override var mode: Operation.Mode
) : BaseOperation<State>() {

override fun isApplicable(state: GridPuzzleModel.State): Boolean =
override fun isApplicable(state: State): Boolean =
true

override fun createFromState(baseLineState: GridPuzzleModel.State): GridPuzzleModel.State =
override fun createFromState(baseLineState: State): State =
baseLineState

override fun createTargetState(fromState: GridPuzzleModel.State): GridPuzzleModel.State =
override fun createTargetState(fromState: State): State =
fromState.copy(
puzzleMode = GridPuzzleModel.PuzzleMode.SCATTERED
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,27 @@ package com.bumble.puzzyx.composable
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.absoluteOffset
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.withFrameMillis
import androidx.compose.ui.BiasAlignment
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import com.bumble.appyx.interactions.core.ui.math.smoothstep
Expand All @@ -29,78 +34,92 @@ import com.bumble.puzzyx.model.Entry
import com.bumble.puzzyx.model.entries
import com.bumble.puzzyx.ui.appyx_dark
import kotlinx.coroutines.isActive
import kotlin.math.max
import kotlin.math.roundToInt
import kotlin.random.Random

@Immutable
private data class StarFieldSpecs(
val regularStarCounter: Int = 200,
val maxEntries: Int = 12,
val speed: Float = 0.1f,
val zNewCoord: Float = 0f,
val zNewCoord: Float = -1f,
val zFadeInStart: Float = 0.3f,
val zFadeInEnd: Float = 0.4f,
val zFadeOutStart: Float = 1.3f,
val zFadeOutEnd: Float = 1.4f,
) {
val zOffset = (zFadeOutEnd - zFadeInStart) / maxEntries
}

private data class Star(
val xCoord: Float = Random.nextDouble(-0.5, 0.5).toFloat(),
val yCoord: Float = Random.nextDouble(-0.5, 0.5).toFloat(),
val zCoord: Float,
val size: Modifier,
val type: StarType,
)

@Immutable
private sealed class Star {
abstract val xCoord: Float
abstract val yCoord: Float
abstract val zCoord: Float

data class EntryStar(
override val xCoord: Float = Random.nextDouble(-1.0, 1.0).toFloat(),
override val yCoord: Float = Random.nextDouble(-1.0, 1.0).toFloat(),
override val zCoord: Float,
val entry: Entry,
) : Star()

data class RegularStar(
override val xCoord: Float = Random.nextDouble(-1.0, 1.0).toFloat(),
override val yCoord: Float = Random.nextDouble(-1.0, 1.0).toFloat(),
override val zCoord: Float,
val color: Color,
) : Star()
private sealed class StarType {
data class RegularType(val color: Color) : StarType() {
companion object {
val size: Modifier = Modifier.size(4.dp)
}
}

data class EntryType(val entry: Entry) : StarType() {
companion object {
val size: Modifier = Modifier.fillMaxSize(0.15f).aspectRatio(1.5f)
}
}

fun calcZNewCoord(zFadeInStart: Float, zOffset: Float, maxEntries: Int): Float =
when (this) {
is RegularType -> zFadeInStart
is EntryType -> zFadeInStart - zOffset * max(0, entries.size - maxEntries)
}
}

@Immutable
private data class StarField(
val specs: StarFieldSpecs,
val stars: ImmutableList<Star>
val stars: ImmutableList<Star>,
) {
companion object {
fun generateStars(starFieldSpecs: StarFieldSpecs): StarField =
StarField(
specs = starFieldSpecs,
stars = (entryStars(starFieldSpecs) + regularStars(starFieldSpecs))
.shuffled()
.toImmutableList()
stars = (regularStars(starFieldSpecs)
+ entryStars(starFieldSpecs)
).toImmutableList()
)

private fun entryStars(starFieldSpecs: StarFieldSpecs) =
entries.map {
Star.EntryStar(
zCoord = Random.nextDouble(
from = starFieldSpecs.zNewCoord.toDouble(),
until = starFieldSpecs.zFadeOutEnd.toDouble(),
).toFloat(),
entry = it,
)
}

private fun regularStars(starFieldSpecs: StarFieldSpecs) =
Array(starFieldSpecs.regularStarCounter) {
Star.RegularStar(
Star(
zCoord = Random.nextDouble(
from = starFieldSpecs.zNewCoord.toDouble(),
until = starFieldSpecs.zFadeOutEnd.toDouble(),
).toFloat(),
color = Color(
red = Random.nextDouble(0.60, 0.66).toFloat(),
green = Random.nextDouble(0.60, 0.66).toFloat(),
blue = Random.nextDouble(0.97, 1.0).toFloat(),
size = StarType.RegularType.size,
type = StarType.RegularType(
color = Color(
red = Random.nextDouble(0.60, 0.66).toFloat(),
green = Random.nextDouble(0.60, 0.66).toFloat(),
blue = Random.nextDouble(0.97, 1.0).toFloat(),
)
),
)
}.toList()

private fun entryStars(starFieldSpecs: StarFieldSpecs) =
entries.reversed().mapIndexed { index, entry ->
Star(
zCoord = starFieldSpecs.zFadeInStart - index * starFieldSpecs.zOffset,
size = StarType.EntryType.size,
type = StarType.EntryType(entry = entry),
)
}
}
}
Expand All @@ -111,12 +130,19 @@ private fun StarField.update(
): StarField =
copy(
stars = stars.map { star ->
val zNewCoord =
(star.zCoord + specs.speed * timeInSecs).takeIf { it < specs.zFadeOutEnd }
?: specs.zNewCoord
when (star) {
is Star.EntryStar -> star.copy(zCoord = zNewCoord)
is Star.RegularStar -> star.copy(zCoord = zNewCoord)
val zUpdatedCoord = star.zCoord + specs.speed * timeInSecs
if (zUpdatedCoord < specs.zFadeOutEnd) {
star.copy(zCoord = zUpdatedCoord)
} else {
star.copy(
xCoord = Random.nextDouble(-0.5, 0.5).toFloat(),
yCoord = Random.nextDouble(-0.5, 0.5).toFloat(),
zCoord = star.type.calcZNewCoord(
specs.zFadeInStart,
specs.zOffset,
specs.maxEntries
),
)
}
}.toImmutableList()
)
Expand Down Expand Up @@ -155,58 +181,71 @@ private fun StarFieldContent(
starField: StarField,
modifier: Modifier = Modifier,
) {
Box(modifier = modifier) {
starField.stars.forEach { star ->
val zPos = star.zCoord
val xPos = star.xCoord * zPos
val yPos = star.yCoord * zPos
val alpha = smoothstep(starField.specs.zFadeInStart, starField.specs.zFadeInEnd, zPos) -
smoothstep(starField.specs.zFadeOutStart, starField.specs.zFadeOutEnd, zPos)

StarContent(
star,
modifier = Modifier
.scale(zPos)
.size(290.dp)
.aspectRatio(1.5f)
.align(BiasAlignment(xPos, yPos))
.alpha(alpha)
.zIndex(zPos)
)
var size by remember { mutableStateOf(IntSize.Zero) }
Box(
modifier = modifier.onSizeChanged { size = it },
) {
starField.stars.forEachIndexed { index, star ->
key(index) {
val zPos = star.zCoord
val xPos = star.xCoord * zPos
val yPos = star.yCoord * zPos
val alpha = starField.specs.calcAlpha(zPos)
if (alpha > 0f) {
StarContent(
star.type,
modifier = Modifier
.scale(zPos)
.then(star.size)
.align(Alignment.Center)
.absoluteOffset {
IntOffset(
x = (size.width * xPos).roundToInt(),
y = (size.height * yPos).roundToInt(),
)
}
.alpha(alpha)
.zIndex(zPos)
)
}
}
}
}
}

private fun StarFieldSpecs.calcAlpha(zPos: Float) =
smoothstep(zFadeInStart, zFadeInEnd, zPos) - smoothstep(zFadeOutStart, zFadeOutEnd, zPos)

@Composable
private fun StarContent(
star: Star,
type: StarType,
modifier: Modifier = Modifier,
) {
when (star) {
is Star.EntryStar -> EntryStarContent(star, modifier)
is Star.RegularStar -> RegularStarContent(star, modifier)
when (type) {
is StarType.RegularType -> RegularStarContent(type.color, modifier)
is StarType.EntryType -> EntryStarContent(type.entry, modifier)
}
}

@Composable
private fun EntryStarContent(
star: Star.EntryStar,
entry: Entry,
modifier: Modifier = Modifier,
) {
EntryCard(
entry = star.entry,
entry = entry,
modifier = modifier
)
}

@Composable
private fun RegularStarContent(
star: Star.RegularStar,
color: Color,
modifier: Modifier = Modifier,
) {
Canvas(
modifier = modifier
) {
drawCircle(color = star.color, radius = density * 2f)
drawCircle(color = color, radius = density * 2f)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ val entries = listOf(
.background(color)
)
}
)
),
)

val puzzle1Entries = entries
Expand Down
Loading

0 comments on commit aaacb91

Please sign in to comment.