diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..ed8ebcba --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,27 @@ +name: Build + +on: [push] + +env: + CI: + +jobs: + build: + name: Build + runs-on: macos-13 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: '17' + - uses: gradle/wrapper-validation-action@v1 + - uses: gradle/gradle-build-action@v2 + - name: Build + run: ./gradlew :desktopApp:packageReleaseStripArchitecture + - name: Upload distributable + uses: actions/upload-artifact@v3 + with: + name: Distributable + path: | + desktopApp/build/distributable/ diff --git a/desktopApp/build.gradle.kts b/desktopApp/build.gradle.kts index bbaeaca8..d6a1bec3 100644 --- a/desktopApp/build.gradle.kts +++ b/desktopApp/build.gradle.kts @@ -14,8 +14,13 @@ kotlin { sourceSets { val desktopMain by getting { dependencies { + // Tricky way to ensure CI builds ARM64 artifacts + val isCIPresent = providers.environmentVariable("CI").isPresent + val composeDependency = + if (isCIPresent) compose.desktop.macos_arm64 else compose.desktop.currentOs + implementation(project(":shared")) - implementation(compose.desktop.currentOs) + implementation(composeDependency) implementation(libs.appyx.navigation) implementation(libs.kotlin.coroutines.core) implementation(libs.kotlin.coroutines.swing) @@ -31,8 +36,24 @@ compose.desktop { nativeDistributions { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) - packageName = "desktopApp" + packageName = "puzzyx-desktop" packageVersion = "1.0.0" } } } + +tasks.register("packageReleaseStripArchitecture") { + from("build/compose/jars") + // Due to GitHub Actions' lack of support for arm64 macOS virtual machines, we've removed + // the architecture component from our distributable filename. We've enforced the use of + // the arm64 architecture in our dependencies, as shown in 'dependencies' section above. + rename { + it.split("-").run { + slice(0 until size - 2) + last() + }.joinToString("-") + } + into("build/distributable") +}.configure { + dependsOn(tasks.named("packageReleaseUberJarForCurrentOS")) +} + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c469a339..b750ad09 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -64,6 +64,7 @@ google-accompanist-flow = { module = "com.google.accompanist:accompanist-flowlay google-material = "com.google.android.material:material:1.4.0" compose-image-loader = { module = "io.github.qdsfdhvh:image-loader", version.ref = "image-loader-version"} junit = "junit:junit:4.13.2" +k5-compose = "me.nikhilchaudhari:k5-compose:1.0.1" kotlin-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" } kotlin-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } kotlin-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "coroutines" } diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 143c42e2..d3075e01 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -31,6 +31,7 @@ kotlin { api(libs.compose.image.loader) @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class) implementation(compose.components.resources) + implementation(libs.k5.compose) } } val commonTest by getting { diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/backstackclipper/BackStackClipper.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/backstackclipper/BackStackClipper.kt similarity index 97% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/component/backstackclipper/BackStackClipper.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/backstackclipper/BackStackClipper.kt index 781d0bd9..ba446de1 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/backstackclipper/BackStackClipper.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/backstackclipper/BackStackClipper.kt @@ -1,4 +1,4 @@ -package com.bumble.puzzyx.component.backstackclipper +package com.bumble.puzzyx.appyx.component.backstackclipper import androidx.compose.animation.core.SpringSpec import androidx.compose.runtime.Composable diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/backstackclipper/ClipShapeProgress.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/backstackclipper/ClipShapeProgress.kt similarity index 97% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/component/backstackclipper/ClipShapeProgress.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/backstackclipper/ClipShapeProgress.kt index 88911f53..7402d079 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/backstackclipper/ClipShapeProgress.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/backstackclipper/ClipShapeProgress.kt @@ -1,4 +1,4 @@ -package com.bumble.puzzyx.component.backstackclipper +package com.bumble.puzzyx.appyx.component.backstackclipper import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.AnimationVector1D diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/backstackclipper/TargetUiState.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/backstackclipper/TargetUiState.kt similarity index 94% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/component/backstackclipper/TargetUiState.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/backstackclipper/TargetUiState.kt index 59d5a0be..ebd4362a 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/backstackclipper/TargetUiState.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/backstackclipper/TargetUiState.kt @@ -1,4 +1,4 @@ -package com.bumble.puzzyx.component.backstackclipper +package com.bumble.puzzyx.appyx.component.backstackclipper import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Shape diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/GridPuzzle.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/GridPuzzle.kt similarity index 88% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/GridPuzzle.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/GridPuzzle.kt index 85271f87..8c6eb312 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/GridPuzzle.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/GridPuzzle.kt @@ -1,10 +1,10 @@ -package com.bumble.puzzyx.component.gridpuzzle +package com.bumble.puzzyx.appyx.component.gridpuzzle import androidx.compose.animation.core.SpringSpec import com.bumble.appyx.interactions.core.model.BaseAppyxComponent import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec import com.bumble.appyx.navigation.state.SavedStateMap -import com.bumble.puzzyx.puzzle.PuzzlePiece +import com.bumble.puzzyx.model.PuzzlePiece class GridPuzzle( savedStateMap: SavedStateMap? = null, diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/GridPuzzleModel.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/GridPuzzleModel.kt similarity index 89% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/GridPuzzleModel.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/GridPuzzleModel.kt index 7595ca73..edc905cf 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/GridPuzzleModel.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/GridPuzzleModel.kt @@ -1,4 +1,4 @@ -package com.bumble.puzzyx.component.gridpuzzle +package com.bumble.puzzyx.appyx.component.gridpuzzle import com.bumble.appyx.interactions.core.Element import com.bumble.appyx.interactions.core.Elements @@ -7,8 +7,8 @@ import com.bumble.appyx.interactions.core.model.transition.BaseTransitionModel import com.bumble.appyx.navigation.state.SavedStateMap import com.bumble.appyx.utils.multiplatform.Parcelable import com.bumble.appyx.utils.multiplatform.Parcelize -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel.PuzzleMode.SCATTERED -import com.bumble.puzzyx.puzzle.PuzzlePiece +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel.PuzzleMode.SCATTERED +import com.bumble.puzzyx.model.PuzzlePiece class GridPuzzleModel( savedStateMap: SavedStateMap? = null, diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/GridPuzzleVisualisation.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/GridPuzzleVisualisation.kt similarity index 93% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/GridPuzzleVisualisation.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/GridPuzzleVisualisation.kt index 8a682160..9448fd6f 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/GridPuzzleVisualisation.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/GridPuzzleVisualisation.kt @@ -1,4 +1,4 @@ -package com.bumble.puzzyx.component.gridpuzzle +package com.bumble.puzzyx.appyx.component.gridpuzzle import androidx.compose.animation.core.Easing import androidx.compose.animation.core.SpringSpec @@ -16,12 +16,12 @@ import com.bumble.appyx.interactions.core.ui.property.impl.position.BiasAlignmen import com.bumble.appyx.interactions.core.ui.property.impl.position.PositionInside.Target import com.bumble.appyx.interactions.core.ui.state.MatchedTargetUiState import com.bumble.appyx.transitionmodel.BaseMotionController -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel.PuzzleMode.ASSEMBLED -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel.PuzzleMode.CAROUSEL -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel.PuzzleMode.FLIPPED -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel.PuzzleMode.SCATTERED -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel.State -import com.bumble.puzzyx.puzzle.PuzzlePiece +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel.PuzzleMode.ASSEMBLED +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel.PuzzleMode.CAROUSEL +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel.PuzzleMode.FLIPPED +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel.PuzzleMode.SCATTERED +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel.State +import com.bumble.puzzyx.model.PuzzlePiece import kotlin.math.min import kotlin.random.Random diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/TargetUiState.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/TargetUiState.kt similarity index 94% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/TargetUiState.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/TargetUiState.kt index 1eba2bf6..4d7018ff 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/TargetUiState.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/TargetUiState.kt @@ -1,4 +1,4 @@ -package com.bumble.puzzyx.component.gridpuzzle +package com.bumble.puzzyx.appyx.component.gridpuzzle import com.bumble.appyx.interactions.core.ui.property.impl.AngularPosition import com.bumble.appyx.interactions.core.ui.property.impl.RotationY diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Assemble.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Assemble.kt similarity index 72% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Assemble.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Assemble.kt index c6fff478..a5bd74c5 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Assemble.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Assemble.kt @@ -1,14 +1,12 @@ -package com.bumble.puzzyx.component.gridpuzzle.operation +package com.bumble.puzzyx.appyx.component.gridpuzzle.operation import androidx.compose.animation.core.AnimationSpec -import com.bumble.appyx.components.backstack.BackStack -import com.bumble.appyx.components.backstack.operation.Push import com.bumble.appyx.interactions.core.model.transition.BaseOperation import com.bumble.appyx.interactions.core.model.transition.Operation import com.bumble.appyx.utils.multiplatform.Parcelize -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzle -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel.State +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzle +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel.State @Parcelize class Assemble( diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Carousel.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Carousel.kt similarity index 77% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Carousel.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Carousel.kt index 684aaa2e..43b86ae0 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Carousel.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Carousel.kt @@ -1,12 +1,12 @@ -package com.bumble.puzzyx.component.gridpuzzle.operation +package com.bumble.puzzyx.appyx.component.gridpuzzle.operation import androidx.compose.animation.core.AnimationSpec import com.bumble.appyx.interactions.core.model.transition.BaseOperation import com.bumble.appyx.interactions.core.model.transition.Operation import com.bumble.appyx.utils.multiplatform.Parcelize -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzle -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel.State +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzle +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel.State @Parcelize class Carousel( diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Flip.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Flip.kt similarity index 72% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Flip.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Flip.kt index 00907e4d..ab5fe3bc 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Flip.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Flip.kt @@ -1,14 +1,12 @@ -package com.bumble.puzzyx.component.gridpuzzle.operation +package com.bumble.puzzyx.appyx.component.gridpuzzle.operation import androidx.compose.animation.core.AnimationSpec -import com.bumble.appyx.components.backstack.BackStack -import com.bumble.appyx.components.backstack.operation.Push import com.bumble.appyx.interactions.core.model.transition.BaseOperation import com.bumble.appyx.interactions.core.model.transition.Operation import com.bumble.appyx.utils.multiplatform.Parcelize -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzle -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel.State +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzle +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel.State @Parcelize class Flip( diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Scatter.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Scatter.kt similarity index 77% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Scatter.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Scatter.kt index a05ca55f..297e045d 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/component/gridpuzzle/operation/Scatter.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/appyx/component/gridpuzzle/operation/Scatter.kt @@ -1,12 +1,12 @@ -package com.bumble.puzzyx.component.gridpuzzle.operation +package com.bumble.puzzyx.appyx.component.gridpuzzle.operation import androidx.compose.animation.core.AnimationSpec import com.bumble.appyx.interactions.core.model.transition.BaseOperation import com.bumble.appyx.interactions.core.model.transition.Operation import com.bumble.appyx.utils.multiplatform.Parcelize -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzle -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzleModel.State +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzle +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzleModel.State @Parcelize class Scatter( diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/composable/EntryCard.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/composable/EntryCard.kt index d2807e38..71621c6a 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/composable/EntryCard.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/composable/EntryCard.kt @@ -1,18 +1,103 @@ package com.bumble.puzzyx.composable +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import com.bumble.puzzyx.entries.Entry +import androidx.compose.ui.unit.sp +import com.bumble.puzzyx.model.Entry +import com.bumble.puzzyx.imageloader.ResourceImage +import com.bumble.puzzyx.ui.colors @Composable fun EntryCard( modifier: Modifier, entry: Entry +) { + Box( + modifier = modifier.clip(RoundedCornerShape(16.dp)) + ) { + when (entry) { + is Entry.Text -> TextEntry(entry) + is Entry.Image -> ResourceImage( + path = "participant/${entry.path}", + contentDescription = entry.contentDescription, + contentScale = entry.contentScale, + modifier = Modifier.fillMaxSize().align(Alignment.Center) + ) + is Entry.ComposableContent -> entry.content() + } + GitHubHeader( + entry = entry, + modifier = Modifier.padding(8.dp) + ) + } +} + +@Composable +fun GitHubHeader( + entry: Entry, + modifier: Modifier = Modifier +) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + ) { + ResourceImage( + path = "github.png", + contentScale = ContentScale.Inside, + modifier = Modifier + .size(32.dp) + .padding(2.dp) + ) + Spacer( + modifier = Modifier.size(4.dp) + ) + Text( + text = entry.githubUserName, + fontSize = 18.sp, + fontWeight = FontWeight.Bold + ) + } +} + +@Composable +fun TextEntry( + entry: Entry.Text, + modifier: Modifier = Modifier +) { + val colorIdx = remember { colors.indices.random() } + + Text( + text = entry.message, + fontSize = 16.sp, + modifier = modifier + .fillMaxSize() + .background(colors[colorIdx]) + .padding(12.dp) + .padding(top = 36.dp) + , + ) +} + +@Composable +fun EntryCardSmall( + modifier: Modifier, + entry: Entry.Text ) { ScaledLayout( modifier = modifier.padding(8.dp), @@ -23,7 +108,6 @@ fun EntryCard( .fillMaxSize() ) { Text(entry.githubUserName) - Text(entry.twitterHandle) Text(entry.message) } } diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/composable/MessageBoard.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/composable/MessageBoard.kt index 3d612808..3e6aa43c 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/composable/MessageBoard.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/composable/MessageBoard.kt @@ -1,24 +1,120 @@ package com.bumble.puzzyx.composable +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.BiasAbsoluteAlignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.bumble.puzzyx.model.entries +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import math.noise3D +import kotlin.math.cos @Composable fun MessageBoard(modifier: Modifier) { + ProgressBasedContent( + millisPerFrame = 50000, + ) { time -> + MessageBoardContent(time, modifier) + } +} + +@Composable +private fun MessageBoardContent(time: Float, modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .background(Color.LightGray) + .padding(64.dp) ) { - Text( - text = "MessageBoard", - modifier = Modifier.align(Alignment.Center) - ) + val maxX = 4 + val maxY = 3 + val xList = remember { (0..maxX).shuffled() } + val yList = remember { (0..maxY).shuffled() } + val entriesShuffled = remember { entries.shuffled() } + + for (x in 0..maxX) { + for (y in 0..maxY) { + val u = 1.0 * x / maxX + val v = 1.0 * y / maxY + val uShuffled = 1.0 * xList[x] / maxX + val vShuffled = 1.0 * yList[y] / maxY + val noise = noise3D(uShuffled, vShuffled, cos(Math.PI * 2 * time)).toFloat() + + Box( + modifier = Modifier + .size(290.dp) + .aspectRatio(1.5f) + .align(BiasAbsoluteAlignment((u * 2 - 1).toFloat(), (v * 2 - 1).toFloat())) + .padding(12.dp) + ) { + AnimatedVisibility( + modifier = Modifier.fillMaxSize().align(Alignment.Center), + visible = noise > 0.02f, + ) { + val entry = entriesShuffled[(y * maxY + x) % entriesShuffled.size] + + EntryCard( + modifier = Modifier.fillMaxSize(), + entry + ) + } + } + } + } } } + +@Composable +fun ProgressBasedContent( + millisPerFrame: Int, + initialDelayMillis: Long = 0, + frameDelayMillis: Long = 0, + content: @Composable (progress: Float) -> Unit +) { + val time = remember { Animatable(0f) } + var inProgress by remember { mutableStateOf(true) } + + LaunchedEffect(Unit) { + delay(initialDelayMillis) + while (isActive) { + delay(frameDelayMillis) + inProgress = true + time.animateTo( + targetValue = time.value + 1f, + animationSpec = tween( + durationMillis = millisPerFrame, + easing = LinearEasing + ), + ) { + inProgress = false + } + } + } + + val fraction = time.value - time.value.toInt() + // To account for actually reaching 100% at the end rather than jumping back to 0%: + val extra = if (!inProgress && time.value > 0 && time.value == time.value.toInt() + .toFloat() + ) 1 else 0 + val progress = fraction + extra + + content(progress) +} diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/entries/Entry.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/entries/Entry.kt deleted file mode 100644 index cc697233..00000000 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/entries/Entry.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.bumble.puzzyx.entries - -data class Entry( - val githubUserName: String = fakeGitHubUserNames.random(), - val twitterHandle: String = fakeTwitterHandles.random(), - val message: String = fakeMessages.random() -) diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/Entries.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/Entries.kt new file mode 100644 index 00000000..29fe43a4 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/Entries.kt @@ -0,0 +1,118 @@ +package com.bumble.puzzyx.model + +import androidx.compose.animation.animateColor +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.RepeatMode +import androidx.compose.animation.core.infiniteRepeatable +import androidx.compose.animation.core.rememberInfiniteTransition +import androidx.compose.animation.core.tween +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import com.bumble.puzzyx.ui.md_indigo_500 +import com.bumble.puzzyx.ui.md_lime_500 + +val entries = listOf( + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "codeNinja", + message = "Having a blast at the conference!" + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "techWanderlust", + message = "Keynote was inspiring" + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "dataGeek", + message = "Shoutout to the organizers for an amazing lineup!" + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "codeCraftsman", + message = "Learning, networking, and free coffee – conference life is good!" + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "byteBender", + message = "Let's connect! Find me at the networking session!" + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "stellarCoder", + message = "L77tc0der was here" + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "codeWaveSurfer", + message = "Mind blown by the innovative ideas shared today." + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "devDreamer", + message = "Great to see old friends and make new ones!" + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "cyberPioneer", + message = "Who's up for a post-conference karaoke session tonight?" + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "codeMaverick", + message = "Kudos to the speakers for keeping us engaged all day." + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "gitGuru", + message = "Highlight of the day: the interactive workshop on Appyx." + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "byteBlaze", + message = "Impressed by the cool tech showcased in the exhibition hall!" + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "bugHuntingHero", + message = "Taking copious notes – my brain might explode!" + ), + Entry.Text( + puzzle = Puzzle.PUZZLE1, + githubUserName = "algoExplorer", + message = "Attending from NYC – making my hometown proud!" + ), + Entry.Image( + puzzle = Puzzle.PUZZLE1, + githubUserName = "codeWhizKid", + path = "cake.png", + contentScale = ContentScale.Crop + ), + Entry.ComposableContent( + puzzle = Puzzle.PUZZLE1, + githubUserName = "codeWhizKid", + content = { + val infiniteTransition = rememberInfiniteTransition() + val color by infiniteTransition.animateColor( + initialValue = md_indigo_500, + targetValue = md_lime_500, + animationSpec = infiniteRepeatable( + animation = tween(500, easing = LinearEasing), + repeatMode = RepeatMode.Reverse + ) + ) + + Box( + modifier = Modifier + .fillMaxSize() + .background(color) + ) + } + ) +) + +val puzzle1Entries = entries.filter { it.puzzle == Puzzle.PUZZLE1 } diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/Entry.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/Entry.kt new file mode 100644 index 00000000..26bbeca7 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/Entry.kt @@ -0,0 +1,29 @@ +package com.bumble.puzzyx.model + +import androidx.compose.runtime.Composable +import androidx.compose.ui.layout.ContentScale + +sealed class Entry { + abstract val puzzle: Puzzle + abstract val githubUserName: String + + data class Text( + override val puzzle: Puzzle, + override val githubUserName: String, + val message: String = fakeMessages.random() + ) : Entry() + + data class Image( + override val puzzle: Puzzle, + override val githubUserName: String, + val path: String, + val contentDescription: String? = null, + val contentScale: ContentScale = ContentScale.Fit + ) : Entry() + + data class ComposableContent( + override val puzzle: Puzzle, + override val githubUserName: String, + val content: @Composable () -> Unit + ) : Entry() +} diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/entries/Entries.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/FakeEntries.kt similarity index 76% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/entries/Entries.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/model/FakeEntries.kt index 92194a7c..50f743af 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/entries/Entries.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/FakeEntries.kt @@ -1,32 +1,4 @@ -package com.bumble.puzzyx.entries - -val fakeTwitterHandles = listOf( - "@tweetNinja", - "@socialWanderer", - "@codeGeek", - "@pixelPioneer", - "@techCraftsman", - "@byteBender", - "@stellarTweeter", - "@waveSurfer", - "@dreamyDev", - "@cyberPioneer", - "@maverickCoder", - "@gitGuru", - "@byteBlaze", - "@bugHuntingHero", - "@artSculptor", - "@algoExplorer", - "@whizKidCoder", - "@pixelPirate", - "@juggleTheCode", - "@scribeData", - "@cyberNomad", - "@alchemyCoder", - "@safariByte", - "@trailblazingTech", - "@voyagingDev" -) +package com.bumble.puzzyx.model val fakeGitHubUserNames = listOf( "codeNinja", @@ -43,7 +15,6 @@ val fakeGitHubUserNames = listOf( "gitGuru", "byteBlaze", "bugHuntingHero", - "techSculptor", "algoExplorer", "codeWhizKid", "pixelPirate", diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/Puzzle.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/Puzzle.kt new file mode 100644 index 00000000..669dfbb3 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/Puzzle.kt @@ -0,0 +1,5 @@ +package com.bumble.puzzyx.model + +enum class Puzzle { + PUZZLE1 +} diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/puzzle/PuzzlePiece.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/PuzzlePiece.kt similarity index 52% rename from shared/src/commonMain/kotlin/com/bumble/puzzyx/puzzle/PuzzlePiece.kt rename to shared/src/commonMain/kotlin/com/bumble/puzzyx/model/PuzzlePiece.kt index f4544ded..df312a7d 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/puzzle/PuzzlePiece.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/model/PuzzlePiece.kt @@ -1,6 +1,4 @@ -package com.bumble.puzzyx.puzzle - -import com.bumble.puzzyx.entries.Entry +package com.bumble.puzzyx.model data class PuzzlePiece( val i: Int, diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/node/app/PuzzyxAppNode.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/node/app/PuzzyxAppNode.kt index ef7b5697..3b1a1887 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/node/app/PuzzyxAppNode.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/node/app/PuzzyxAppNode.kt @@ -28,7 +28,7 @@ import com.bumble.appyx.navigation.node.ParentNode import com.bumble.appyx.navigation.node.node import com.bumble.appyx.utils.multiplatform.Parcelable import com.bumble.appyx.utils.multiplatform.Parcelize -import com.bumble.puzzyx.component.backstackclipper.BackStackClipper +import com.bumble.puzzyx.appyx.component.backstackclipper.BackStackClipper import com.bumble.puzzyx.composable.CallToActionScreen import com.bumble.puzzyx.composable.MessageBoard import com.bumble.puzzyx.node.app.PuzzyxAppNode.NavTarget @@ -38,11 +38,17 @@ import com.bumble.puzzyx.node.app.PuzzyxAppNode.NavTarget.Puzzle1 import com.bumble.puzzyx.node.puzzle1.Puzzle1Node import com.bumble.puzzyx.ui.DottedMeshShape +private val screens = listOf( + Puzzle1, + CallToAction, + MessageBoard +) + class PuzzyxAppNode( buildContext: BuildContext, private val backStack: BackStack = BackStack( model = BackStackModel( - initialTargets = listOf(Puzzle1), + initialTargets = listOf(screens.first()), savedStateMap = buildContext.savedStateMap, ), motionController = { BackStackClipper(it, shape = { progress -> ClipShape(progress) }) } @@ -95,7 +101,6 @@ class PuzzyxAppNode( @Composable private fun NextButton() { - val screens = remember { listOf(Puzzle1, CallToAction, MessageBoard) } var screenIdx by remember { mutableStateOf(0) } Button( diff --git a/shared/src/commonMain/kotlin/com/bumble/puzzyx/node/puzzle1/Puzzle1Node.kt b/shared/src/commonMain/kotlin/com/bumble/puzzyx/node/puzzle1/Puzzle1Node.kt index 435f5eb9..72e57904 100644 --- a/shared/src/commonMain/kotlin/com/bumble/puzzyx/node/puzzle1/Puzzle1Node.kt +++ b/shared/src/commonMain/kotlin/com/bumble/puzzyx/node/puzzle1/Puzzle1Node.kt @@ -30,16 +30,18 @@ import com.bumble.appyx.navigation.modality.BuildContext import com.bumble.appyx.navigation.node.Node import com.bumble.appyx.navigation.node.ParentNode import com.bumble.appyx.navigation.node.node -import com.bumble.puzzyx.component.gridpuzzle.GridPuzzle -import com.bumble.puzzyx.component.gridpuzzle.operation.assemble -import com.bumble.puzzyx.component.gridpuzzle.operation.carousel -import com.bumble.puzzyx.component.gridpuzzle.operation.flip -import com.bumble.puzzyx.component.gridpuzzle.operation.scatter -import com.bumble.puzzyx.composable.EntryCard +import com.bumble.puzzyx.appyx.component.gridpuzzle.GridPuzzle +import com.bumble.puzzyx.appyx.component.gridpuzzle.operation.assemble +import com.bumble.puzzyx.appyx.component.gridpuzzle.operation.carousel +import com.bumble.puzzyx.appyx.component.gridpuzzle.operation.flip +import com.bumble.puzzyx.appyx.component.gridpuzzle.operation.scatter +import com.bumble.puzzyx.composable.EntryCardSmall import com.bumble.puzzyx.composable.FlashCard -import com.bumble.puzzyx.entries.Entry import com.bumble.puzzyx.imageloader.ResourceImage -import com.bumble.puzzyx.puzzle.PuzzlePiece +import com.bumble.puzzyx.model.Entry +import com.bumble.puzzyx.model.Puzzle +import com.bumble.puzzyx.model.PuzzlePiece +import com.bumble.puzzyx.model.puzzle1Entries import com.bumble.puzzyx.ui.appyx_dark import com.bumble.puzzyx.ui.colors import org.jetbrains.compose.resources.ExperimentalResourceApi @@ -58,9 +60,16 @@ class Puzzle1Node( private val gridPuzzle: GridPuzzle = GridPuzzle( gridRows = rows, gridCols = columns, - pieces = IntRange(0, rows * columns - 1).map { - PuzzlePiece(it % columns, it / columns, Entry()) - }.shuffled(),//.take(37), // TODO To test only a subset of elements, uncomment .take + pieces = IntRange(0, rows * columns - 1) + .shuffled(Random(123)) + .take(puzzle1Entries.size) + .mapIndexed { sequentialIdx, shuffledIdx -> + PuzzlePiece( + i = shuffledIdx % columns, + j = shuffledIdx / columns, + entry = puzzle1Entries[sequentialIdx] + ) + }, savedStateMap = buildContext.savedStateMap, defaultAnimationSpec = animationSpec ) @@ -91,11 +100,12 @@ class Puzzle1Node( ) }, back = { modifier -> - EntryCard( + EntryCardSmall( modifier = modifier .fillMaxSize() .background(color), - puzzlePiece.entry + // TODO decide on the fate of this + puzzlePiece.entry as? Entry.Text ?: Entry.Text(Puzzle.PUZZLE1, "n/a") ) } ) diff --git a/shared/src/commonMain/resources/github.png b/shared/src/commonMain/resources/github.png new file mode 100644 index 00000000..93c6a54e Binary files /dev/null and b/shared/src/commonMain/resources/github.png differ diff --git a/shared/src/commonMain/resources/participant/cake.png b/shared/src/commonMain/resources/participant/cake.png new file mode 100644 index 00000000..5a639ae7 Binary files /dev/null and b/shared/src/commonMain/resources/participant/cake.png differ