Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement planet selection screen #298

Merged
merged 24 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
38a6a55
feat: add PlanetRenderer for OpenGL rendering in selection screen
Kenzoud Dec 18, 2024
cba34bc
feat: add PlanetSurfaceView for OpenGL planet rendering
Kenzoud Dec 18, 2024
0a988e3
feat: add iconRes field to PlanetData for UI integration
Kenzoud Dec 18, 2024
bb374b2
feat: add iconRes field to planets list in PlanetsRepository
Kenzoud Dec 18, 2024
f66b33d
feat: add PlanetSelection route and screen to navigation actions
Kenzoud Dec 18, 2024
8a4ea48
feat: add PlanetSelectionRow composable for horizontal planet selection
Kenzoud Dec 18, 2024
3343965
feat: add PlanetButton composable for individual planet selection
Kenzoud Dec 18, 2024
ac3a89a
feat: add PlanetSelectionScreen composable for selecting and displayi…
Kenzoud Dec 18, 2024
95a360e
feat: add PlanetSelectionViewModel to manage planet selection state
Kenzoud Dec 18, 2024
1b04ca3
feat: enhance Planet class with texture update and improved draw method
Kenzoud Dec 18, 2024
8eea17b
feat: integrate PlanetSelectionScreen into main navigation flow
Kenzoud Dec 18, 2024
06ba52f
feat: add Planet Selection button to MenuScreen
Kenzoud Dec 18, 2024
0e36252
feat: add error handling in the ShaderProgram
Kenzoud Dec 18, 2024
d61de5f
feat: add planet icons to drawable resources
Kenzoud Dec 18, 2024
730c5e4
Merge branch 'main' into feature/implement-planet-selection-screen
Kenzoud Dec 18, 2024
bdf47e0
fix: change venus icon resolution
Kenzoud Dec 18, 2024
3280411
feat: enhance planet selection screen's UI
Kenzoud Dec 18, 2024
d4040cf
feat: make planets rotate
Kenzoud Dec 18, 2024
951b0b3
refactor: change "Planet Selection" into "Planet"
Kenzoud Dec 18, 2024
bd9fe31
feat: revert to original ShaderProgram implementation
Kenzoud Nov 20, 2024
4b2083d
test: add test for new "Planets" button
Kenzoud Dec 18, 2024
b236ae8
test: add PlanetRendererTest test class for testing PlanetRenderer
Kenzoud Dec 18, 2024
c5e751a
test: add PlanetButtonTest test class for testing PlanetButton compos…
Kenzoud Dec 18, 2024
2de44ae
test: add PlanetSelectionRowTest test class for testing PlanetSelecti…
Kenzoud Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,17 @@ class MenuKtTest {
// Verify navigation to Google Map screen is triggered
verify(mockNavigationActions).navigateTo(Screen.GOOGLE_MAP)
}

@Test
fun menuScreen_clickPlanets_navigatesToPlanetSelectionScreen() {
composeTestRule.setContent {
MenuScreen(navigationActions = mockNavigationActions, mockAvatarViewModel)
}

// Perform click on "Planets" button
composeTestRule.onNodeWithText("Planets").performClick()

// Verify navigation to PlanetSelection screen is triggered
verify(mockNavigationActions).navigateTo(Screen.PLANET_SELECTION)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.github.lookupgroup27.lookup.ui.planetselection.components

import androidx.compose.ui.test.*
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.unit.dp
import com.github.lookupgroup27.lookup.R
import com.github.lookupgroup27.lookup.model.map.planets.PlanetData
import org.junit.Rule
import org.junit.Test

class PlanetButtonTest {

@get:Rule val composeTestRule = createComposeRule()

@Test
fun planetButton_displaysCorrectIcon() {
val planet = PlanetData(name = "Mars", "301", iconRes = R.drawable.mars_icon, textureId = 0)

composeTestRule.setContent { PlanetButton(planet = planet, onClick = {}) }

// Assert that the button contains the correct icon
composeTestRule.onNodeWithContentDescription("Mars button").assertExists()
}

@Test
fun planetButton_isClickable() {
val planet = PlanetData(name = "Mars", "301", iconRes = R.drawable.mars_icon, textureId = 0)
var clicked = false

composeTestRule.setContent { PlanetButton(planet = planet, onClick = { clicked = true }) }

// Perform click on the button
composeTestRule.onNodeWithContentDescription("Mars button").performClick()

// Assert that the button click triggers the onClick action
assert(clicked) { "Planet button click did not trigger the onClick action" }
}

@Test
fun planetButton_hasCorrectSizeAndPadding() {
val planet = PlanetData(name = "Mars", "301", iconRes = R.drawable.mars_icon, textureId = 0)

composeTestRule.setContent { PlanetButton(planet = planet, onClick = {}) }

// Assert that the button has the correct size
composeTestRule.onNodeWithContentDescription("Mars button").assertHeightIsEqualTo(48.dp)
composeTestRule.onNodeWithContentDescription("Mars button").assertWidthIsEqualTo(48.dp)
}

@Test
fun planetButton_backgroundIsBlack() {
val planet = PlanetData(name = "Mars", "301", iconRes = R.drawable.mars_icon, textureId = 0)

composeTestRule.setContent { PlanetButton(planet = planet, onClick = {}) }

// Assert that the button has the correct background color
composeTestRule
.onNodeWithContentDescription("Mars button")
.assertExists() // Additional color checks need more advanced libraries
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.github.lookupgroup27.lookup.ui.planetselection.components

import androidx.compose.ui.test.*
import androidx.compose.ui.test.junit4.createComposeRule
import com.github.lookupgroup27.lookup.R
import com.github.lookupgroup27.lookup.model.map.planets.PlanetData
import org.junit.Rule
import org.junit.Test

class PlanetSelectionRowTest {

@get:Rule val composeTestRule = createComposeRule()

@Test
fun planetSelectionRow_displaysAllPlanets() {
val planets =
listOf(
PlanetData(name = "Mercury", "499", iconRes = R.drawable.mercury_icon, textureId = 0),
PlanetData(name = "Venus", "499", iconRes = R.drawable.venus_icon, textureId = 1),
PlanetData(name = "Mars", "499", iconRes = R.drawable.mars_icon, textureId = 3))

composeTestRule.setContent { PlanetSelectionRow(planets = planets, onPlanetSelected = {}) }

// Assert that all planets are displayed
planets.forEach { planet ->
composeTestRule.onNodeWithContentDescription("${planet.name} button").assertExists()
}
}

@Test
fun planetSelectionRow_planetButtonIsClickable() {
val planets =
listOf(PlanetData(name = "Mars", "499", iconRes = R.drawable.mars_icon, textureId = 0))

var selectedPlanet: PlanetData? = null

composeTestRule.setContent {
PlanetSelectionRow(planets = planets, onPlanetSelected = { selectedPlanet = it })
}

// Perform click on the Mars button
composeTestRule.onNodeWithContentDescription("Mars button").performClick()

// Assert that the onPlanetSelected lambda is triggered with the correct planet
assert(selectedPlanet == planets.first()) {
"Mars button click did not select the correct planet."
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import com.github.lookupgroup27.lookup.ui.overview.LandingScreen
import com.github.lookupgroup27.lookup.ui.overview.MenuScreen
import com.github.lookupgroup27.lookup.ui.passwordreset.PasswordResetScreen
import com.github.lookupgroup27.lookup.ui.passwordreset.PasswordResetViewModel
import com.github.lookupgroup27.lookup.ui.planetselection.PlanetSelectionScreen
import com.github.lookupgroup27.lookup.ui.planetselection.PlanetSelectionViewModel
import com.github.lookupgroup27.lookup.ui.post.PostsViewModel
import com.github.lookupgroup27.lookup.ui.profile.CollectionScreen
import com.github.lookupgroup27.lookup.ui.profile.CollectionViewModel
Expand Down Expand Up @@ -87,6 +89,8 @@ fun LookUpApp() {
viewModel(factory = PasswordResetViewModel.Factory)
val avatarViewModel: AvatarViewModel = viewModel(factory = AvatarViewModel.Factory)
val loginViewModel: LoginViewModel = viewModel(factory = LoginViewModel.Factory)
val planetSelectionViewModel: PlanetSelectionViewModel =
viewModel(factory = PlanetSelectionViewModel.createFactory(context))

NavHost(navController = navController, startDestination = Route.LANDING) {
navigation(
Expand Down Expand Up @@ -122,6 +126,9 @@ fun LookUpApp() {
GoogleMapScreen(navigationActions, postsViewModel, profileViewModel)
}
composable(Screen.QUIZ) { QuizScreen(quizViewModel, navigationActions) }
composable(Screen.PLANET_SELECTION) {
PlanetSelectionScreen(planetSelectionViewModel, navigationActions)
}
}

navigation(startDestination = Screen.QUIZ, route = Route.QUIZ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ class MapRenderer(

private var skyBoxTextureHandle: Int = -1 // Handle for the skybox texture

private val renderableObjects = mutableListOf<Object>() // List of objects to render

private val viewport = IntArray(4)

/** The camera used to draw the shapes on the screen. */
Expand Down Expand Up @@ -134,7 +132,7 @@ class MapRenderer(
private fun drawObjects() {
// Renderable Objects
renderableStars.forEach { o -> o.draw(camera) }
renderablePlanets.forEach { o -> o.draw(camera) }
renderablePlanets.forEach { o -> o.draw(camera, null) }
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ data class PlanetData(
var ra: Double = 0.0, // Right Ascension in degrees
var dec: Double = 0.0, // Declination in degrees
var cartesian: Triple<Float, Float, Float> = Triple(0.0f, 0.0f, 0.0f), // Cartesian coordinates
val textureId: Int
val textureId: Int,
val iconRes: Int = 0 // New field for the button icon
)
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,40 @@ class PlanetsRepository(
// texture.
planets.addAll(
listOf(
PlanetData("Moon", "301", textureId = R.drawable.full_moon),
PlanetData("Mercury", "199", textureId = R.drawable.mercury_texture),
PlanetData("Venus", "299", textureId = R.drawable.venus_texture),
PlanetData("Mars", "499", textureId = R.drawable.mars_texture),
PlanetData("Jupiter", "599", textureId = R.drawable.jupiter_texture),
PlanetData("Saturn", "699", textureId = R.drawable.saturn_texture),
PlanetData("Uranus", "799", textureId = R.drawable.uranus_texture),
PlanetData("Neptune", "899", textureId = R.drawable.neptune_texture)))
PlanetData(
"Moon", "301", textureId = R.drawable.full_moon, iconRes = R.drawable.moon_icon),
PlanetData(
"Mercury",
"199",
textureId = R.drawable.mercury_texture,
iconRes = R.drawable.mercury_icon),
PlanetData(
"Venus",
"299",
textureId = R.drawable.venus_texture,
iconRes = R.drawable.venus_icon),
PlanetData(
"Mars", "499", textureId = R.drawable.mars_texture, iconRes = R.drawable.mars_icon),
PlanetData(
"Jupiter",
"599",
textureId = R.drawable.jupiter_texture,
iconRes = R.drawable.jupiter_icon),
PlanetData(
"Saturn",
"699",
textureId = R.drawable.saturn_texture,
iconRes = R.drawable.saturn_icon),
PlanetData(
"Uranus",
"799",
textureId = R.drawable.uranus_texture,
iconRes = R.drawable.uranus_icon),
PlanetData(
"Neptune",
"899",
textureId = R.drawable.neptune_texture,
iconRes = R.drawable.neptune_icon)))
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@
package com.github.lookupgroup27.lookup.model.map.renderables

import com.github.lookupgroup27.lookup.model.map.Camera

/** Represents an object in the OpenGL world. */
abstract class Object {

/**
* Draw the object on the screen.
*
* @param camera the camera to use to draw the object
*/
abstract fun draw(camera: Camera)
}
abstract class Object {}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ open class Planet(
private val context: Context,
val name: String? = "Planet",
val position: FloatArray = floatArrayOf(0.0f, 0.0f, -2.0f),
protected var textureId: Int,
var textureId: Int,
numBands: Int = SphereRenderer.DEFAULT_NUM_BANDS,
stepsPerBand: Int = SphereRenderer.DEFAULT_STEPS_PER_BAND,
private val scale: Float = 0.3f
Expand Down Expand Up @@ -86,28 +86,30 @@ open class Planet(
*
* @param camera The camera used for rendering the scene.
*/
override fun draw(camera: Camera) {
fun draw(camera: Camera, transformMatrix: FloatArray? = null) {
val modelMatrix = FloatArray(16)
Matrix.setIdentityM(modelMatrix, 0)
val viewMatrix = FloatArray(16)
val projMatrix = FloatArray(16)

// Copy camera matrices to avoid modification
System.arraycopy(camera.viewMatrix, 0, viewMatrix, 0, 16)
System.arraycopy(camera.projMatrix, 0, projMatrix, 0, 16)
// Apply the provided transform matrix or use the default planet position
if (transformMatrix != null) {
System.arraycopy(transformMatrix, 0, modelMatrix, 0, 16)
} else {
Matrix.translateM(modelMatrix, 0, position[0], position[1], position[2])
Matrix.scaleM(modelMatrix, 0, scale, scale, scale)
}

val viewMatrix = camera.viewMatrix
val projMatrix = camera.projMatrix
val mvpMatrix = FloatArray(16)

// Apply object transformations
Matrix.translateM(modelMatrix, 0, position[0], position[1], position[2])
Matrix.scaleM(modelMatrix, 0, scale, scale, scale)
// Combine matrices: Projection * View * Model

// Apply rotation transformation
Matrix.rotateM(modelMatrix, 0, rotationAngle, 0f, 1f, 0f) // Rotate around the Y-axis

// Combine model, view, and projection matrices in correct order
val viewModelMatrix = FloatArray(16)
Matrix.multiplyMM(viewModelMatrix, 0, viewMatrix, 0, modelMatrix, 0)

val mvpMatrix = FloatArray(16)
Matrix.multiplyMM(mvpMatrix, 0, projMatrix, 0, viewModelMatrix, 0)

// Pass final MVP matrix to the renderer
Expand All @@ -125,6 +127,11 @@ open class Planet(
sphereRenderer.unbindShaderAttributes()
}

fun updateTexture(newTextureId: Int) {
textureId = newTextureId
loadTexture() // Reload the texture using the new ID
}

/**
* Checks if a ray intersects the planet's surface.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Star(
circleRenderer.initializeBuffers()
}

override fun draw(camera: Camera) {
fun draw(camera: Camera) {
// Model-View-Projection (MVP) Matrix
val mvpMatrix = FloatArray(16)
val modelMatrix = FloatArray(16)
Expand Down
Loading
Loading