Skip to content

Profile and edit profile screen UI#106

Open
mqiu90 wants to merge 2 commits intomainfrom
profile-ui
Open

Profile and edit profile screen UI#106
mqiu90 wants to merge 2 commits intomainfrom
profile-ui

Conversation

@mqiu90
Copy link

@mqiu90 mqiu90 commented Mar 4, 2026

Summary by CodeRabbit

  • New Features

    • Added Profile screen displaying user information and bookmarked games
    • Added Edit Profile screen for updating user name and details
    • Added Profile navigation tab accessible from the main navigation bar
  • Improvements

    • Replaced carousel pager UI with horizontal scroll list for improved navigation
    • Enhanced navigation bar to support both resource icons and vector icons

@mqiu90 mqiu90 requested a review from amjiao March 4, 2026 22:54
@EmilJiang EmilJiang self-assigned this Mar 13, 2026
@AndrewCheung360
Copy link
Member

@coderabbitai

@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

@AndrewCheung360 Sure! I'll review the pull request now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

📝 Walkthrough

Walkthrough

This change introduces a new Profile feature with navigation support by adding ProfileScreen and EditProfileScreen composables. It refactors GamesCarousel to use LazyRow instead of HorizontalPager, adds dependency updates, extends navigation infrastructure to support profile routes and ImageVector icons, and removes the DotIndicator composable.

Changes

Cohort / File(s) Summary
Dependencies & Configuration
app/build.gradle.kts, gradle/libs.versions.toml
Added Foundation library and Material Icons Extended 1.6.0 dependencies; introduced foundationVersion reference in versions config.
Navigation Infrastructure
app/src/main/java/com/cornellappdev/score/nav/RootNavigation.kt
Added Profile and EditProfile sealed class cases to ScoreScreens; modified NavItem icon types from Int to Any to support both resource IDs and ImageVectors; added Profile tab with Person icons; updated screen mapping and bottom bar logic to exclude EditProfile from bottom navigation.
Navigation Routes
app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt
Added composable routes for Profile and EditProfile screens with appropriate callbacks (navigateToEditProfile and onBackClick).
Navigation Bar Enhancement
app/src/main/java/com/cornellappdev/score/nav/ScoreNavigationBar.kt
Extended icon rendering to support both Int resource IDs and ImageVector types with conditional tinting (CrimsonPrimary when selected, GrayPrimary when unselected) for vector icons.
UI Component Refactor
app/src/main/java/com/cornellappdev/score/components/GamesCarousel.kt
Replaced HorizontalPager-based carousel with LazyRow; removed PagerState management and DotIndicator composable; simplified item rendering with fixed 300.dp width for FeaturedGameCard.
New Profile Screens
app/src/main/java/com/cornellappdev/score/screen/ProfileScreen.kt, app/src/main/java/com/cornellappdev/score/screen/EditProfileScreen.kt
Added ProfileScreen with top bar, profile row, and two game carousel sections (Bookmarks and Games You Might Like); added EditProfileScreen with back navigation, photo placeholder, editable name/username fields, and save button.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant ProfileScreen
    participant Navigation
    participant EditProfileScreen

    User->>ProfileScreen: View profile
    Note over ProfileScreen: Display profile info,<br/>bookmarks & recommendations
    User->>ProfileScreen: Click Edit Profile
    ProfileScreen->>Navigation: navigateToEditProfile()
    Navigation->>EditProfileScreen: Navigate
    User->>EditProfileScreen: Edit name/username
    User->>EditProfileScreen: Tap Save
    EditProfileScreen->>Navigation: onBackClick()
    Navigation->>ProfileScreen: Navigate back
    ProfileScreen->>User: Show updated profile
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 Hopping through the profile feature spring,
New screens bloom where navigation routes sing,
LazyRow spins where the pager once danced,
With icons that glow when selected or glanced,
The score app's wardrobe is richly enhanced!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is completely missing. The template requires Overview, Changes Made, and Test Coverage sections at minimum. Add a comprehensive description following the repository template, including Overview, Changes Made, and Test Coverage sections to document the new screens and UI implementation.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: adding UI for profile and edit profile screens, which is the primary focus of the entire changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch profile-ui
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can approve the review once all CodeRabbit's comments are resolved.

Enable the reviews.request_changes_workflow setting to automatically approve the review once all CodeRabbit's comments are resolved.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (8)
app/src/main/java/com/cornellappdev/score/screen/ProfileScreen.kt (3)

81-84: Placeholder onClick handlers need implementation.

The onClick callbacks for both GamesCarousel instances contain placeholder comments. These should be wired to navigate to game details (similar to other screens using navigateToGameDetails).

Would you like me to suggest how to wire these to navigation, similar to HomeScreen and PastGamesScreen?

Also applies to: 117-120

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/screen/ProfileScreen.kt` around
lines 81 - 84, The two GamesCarousel components in ProfileScreen (the one at
games = bookmarkedGames and the other at games = createdGames) use placeholder
onClick handlers; replace those comments by invoking the app's navigation helper
(e.g., call navigateToGameDetails(gameId) or the equivalent navigation function
used by HomeScreen/PastGamesScreen) so clicking a game navigates to its detail
screen, passing the gameId parameter through the existing navigateToGameDetails
method used elsewhere.

51-84: Extract duplicate section pattern into a reusable composable.

The "Bookmarks" and "Games You Might Like" sections share identical structure (header row with title, count, chevron, and GamesCarousel). Consider extracting:

♻️ Suggested extraction
`@Composable`
private fun GameSection(
    title: String,
    games: List<GameCardData>,
    onClick: (String) -> Unit,
    modifier: Modifier = Modifier
) {
    Row(
        modifier = modifier
            .fillMaxWidth()
            .padding(horizontal = 20.dp),
        horizontalArrangement = Arrangement.SpaceBetween,
        verticalAlignment = Alignment.CenterVertically
    ) {
        Text(
            text = title,
            fontSize = 18.sp,
            fontWeight = FontWeight.Bold,
            color = Color.Black
        )
        Row(verticalAlignment = Alignment.CenterVertically) {
            Text(
                text = "${games.size} Results",
                fontSize = 14.sp,
                color = Color.Gray
            )
            Icon(
                imageVector = Icons.Outlined.ChevronRight,
                contentDescription = null,
                tint = Color.Gray,
                modifier = Modifier.size(18.dp)
            )
        }
    }
    Spacer(modifier = Modifier.height(12.dp))
    GamesCarousel(games = games, onClick = onClick)
}

Also applies to: 87-120

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/screen/ProfileScreen.kt` around
lines 51 - 84, Extract the duplicated header + carousel UI into a private
composable (e.g., GameSection) and replace both the "Bookmarks" block (which
currently uses bookmarkedGames and GamesCarousel) and the "Games You Might Like"
block (which uses the other games list) to call this composable; GameSection
should take title: String, games: List<GameCardData>, onClick: (String) -> Unit,
and optional modifier, render the Row with title, count ("${games.size}
Results"), chevron Icon, a Spacer, then call GamesCarousel(games = games,
onClick = onClick); update usages so bookmarkedGames and the other games list
pass through and remove the duplicated Row/Spacer/GamesCarousel blocks.

192-207: Hardcoded user data in ProfileRow.

The user name "Audrey Wu" and handle "@audreywuu" are hardcoded. This is acceptable for UI scaffolding, but these values should eventually come from a ViewModel or data source.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/screen/ProfileScreen.kt` around
lines 192 - 207, ProfileRow currently hardcodes the display name and handle
("Audrey Wu" and "@audreywuu"); update it to accept and render dynamic data by
wiring the Text composables to source values instead of literals. Modify the
ProfileRow (or enclosing ProfileScreen) composable to take parameters like
userName: String and userHandle: String (or read them from a ViewModel property)
and replace the hardcoded strings in the two Text calls with those
parameters/observed state so the UI reflects the real user data.
app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt (1)

150-151: Using Any type for icons loses type safety.

Changing unselectedIcon and selectedIcon from Int to Any allows both resource IDs and ImageVector, but sacrifices compile-time type checking. Consider a sealed interface:

♻️ Type-safe alternative
sealed interface NavIcon {
    data class Resource(val resId: Int) : NavIcon
    data class Vector(val imageVector: ImageVector) : NavIcon
}

data class NavItem(
    val screen: ScoreScreens,
    val label: String,
    val unselectedIcon: NavIcon,
    val selectedIcon: NavIcon
)

This prevents accidental misuse and makes the API self-documenting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt` around
lines 150 - 151, Replace the two Any-typed icon properties on NavItem
(unselectedIcon and selectedIcon) with a sealed interface NavIcon and use
concrete implementations (e.g., Resource(resId: Int) and Vector(imageVector:
ImageVector)) so callers must supply either a resource id or an ImageVector
explicitly; update NavItem to take NavIcon for both unselectedIcon and
selectedIcon and refactor any creation/consumption sites to pattern-match on
NavIcon (Resource vs Vector) when rendering.
app/src/main/java/com/cornellappdev/score/components/GamesCarousel.kt (1)

30-48: Consider adding a key parameter for stable item identity.

Using items(games) without a key may cause unnecessary recompositions when the list updates. Since GameCardData has an id field (used in onClick), consider:

-        items(games) { game ->
+        items(games, key = { it.id }) { game ->

This helps Compose efficiently diff and animate list changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/components/GamesCarousel.kt` around
lines 30 - 48, The carousel uses items(games) without a stable key which can
cause unnecessary recompositions; update the call to items(...) to provide a
unique key (use the game's id) so Compose can track identities and diff
efficiently — locate the items(games) lambda in GamesCarousel.kt where
FeaturedGameCard is created and change the items invocation to include key = {
game -> game.id } (or the appropriate unique id property from GameCardData) so
list updates and animations are stable.
app/src/main/java/com/cornellappdev/score/nav/ScoreNavigationBar.kt (1)

42-55: Consider adding an else branch or using a sealed type for icons.

The current implementation silently ignores unsupported icon types. If NavItem.unselectedIcon/selectedIcon (typed as Any in RootNavigation.kt) receives an unexpected type, no icon renders. Consider either:

  1. Adding a logging/warning else branch for debugging
  2. Using a sealed class/interface for icon types to ensure compile-time safety

This is low-risk since the current usages are controlled, but would improve maintainability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/nav/ScoreNavigationBar.kt` around
lines 42 - 55, The code in ScoreNavigationBar.kt currently handles two runtime
icon types (Int and ImageVector) for item.selectedIcon/item.unselectedIcon but
silently does nothing for any other type; update the implementation to either
(A) add a clear else branch after the existing checks that logs a warning via
your logger (or calls a fallback Icon) mentioning the NavItem id/title and the
unexpected icon type, or (B) refactor NavItem.selectedIcon/unselectedIcon in
RootNavigation.kt to use a sealed class (e.g., IconResource with subclasses
ResourceId(val id: Int) and VectorIcon(val vector: ImageVector)) and update
ScoreNavigationBar to pattern-match on that sealed type so unsupported cases are
impossible at compile time; reference the item variable,
NavItem.selectedIcon/unselectedIcon, and the Icon composable when making the
change.
app/src/main/java/com/cornellappdev/score/screen/EditProfileScreen.kt (2)

178-179: Save button onClick is not implemented.

The Save button has an empty onClick = { } handler. This should eventually persist the edited name and username, then navigate back.

Would you like me to help outline the save logic integration with a ViewModel?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/screen/EditProfileScreen.kt` around
lines 178 - 179, The Save button in EditProfileScreen has an empty onClick; wire
it to the screen's save flow by calling the ViewModel's save/update method
(e.g., EditProfileViewModel.saveProfile or updateProfile) with the current
editedName/editedUsername state, perform simple validation (non-empty, username
uniqueness check via the ViewModel/repository), await the result, surface errors
via the ViewModel's error state, and on success invoke navigation back (e.g.,
navController.popBackStack() or provided onNavigateUp callback). Ensure the
Button's onClick references the exact state variables used in EditProfileScreen
(editedName, editedUsername) and the ViewModel method name
(saveProfile/updateProfile) so the persistence and navigation happen atomically.

129-142: BasicTextField lacks visual feedback.

BasicTextField without a decorationBox provides no visual indication of focus state or field boundaries. Users may not realize the field is editable. Consider adding a decorationBox parameter or using OutlinedTextField/TextField for better UX.

Also applies to: 160-173

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/screen/EditProfileScreen.kt` around
lines 129 - 142, The BasicTextField usage (the one bound to variable name with
modifier Modifier.weight(1f)) has no visual affordance; replace it with an
OutlinedTextField or TextField (or add a decorationBox) to provide
focus/border/placeholder and proper padding, and ensure you forward the same
textStyle, value/onValueChange, and modifier; do the same for the other
BasicTextField instance referenced (lines ~160-173) so both fields show focus
state and editable bounds.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/build.gradle.kts`:
- Line 84: Remove the duplicate Foundation dependency that causes a version
conflict: delete the implementation(libs.foundation) entry and keep the newer
alias implementation(libs.androidx-foundation) (or vice versa keep only the one
that resolves to version 1.10.3). Ensure only a single
androidx.compose.foundation dependency remains in the dependencies block to
avoid mixing libs.foundation and libs.androidx-foundation.
- Line 107: Remove the explicit version suffix from the implementation
dependency for "androidx.compose.material:material-icons-extended:1.6.0" so it
inherits the version from the Compose BOM (the compose BOM declaration in the
build script), preventing the BOM from being downgraded; locate the dependency
string
"implementation(\"androidx.compose.material:material-icons-extended:1.6.0\")"
and change it to the form without a version so it aligns with the BOM-managed
Compose version.

In `@app/src/main/java/com/cornellappdev/score/screen/EditProfileScreen.kt`:
- Around line 61-68: The back Icon in EditProfileScreen
(Icons.Outlined.ChevronLeft) uses a 24.dp visual size and a clickable modifier,
yielding a touch target smaller than the 48.dp accessibility recommendation;
replace the plain Icon clickable with an IconButton (or wrap the Icon in a Box
with a minimum touch target) so the clickable area meets 48.dp, keep the visual
icon size at 24.dp (e.g., set Icon size to 24.dp while the IconButton/Box
provides the larger touch area) and call onBackClick() from the IconButton's
onClick to preserve behavior.

In `@gradle/libs.versions.toml`:
- Line 22: You have two duplicate aliases for the same
artifact—androidx-foundation and foundation—pointing to different versions;
remove one alias from libs.versions.toml and update the build script imports to
use only the remaining alias (or switch the build to rely on the Compose BOM
instead of an explicit alias); ensure the kept alias/version for
androidx.compose.foundation matches the intended BOM alignment or is
intentionally decoupled so you don’t get conflicting versions on the classpath.

---

Nitpick comments:
In `@app/src/main/java/com/cornellappdev/score/components/GamesCarousel.kt`:
- Around line 30-48: The carousel uses items(games) without a stable key which
can cause unnecessary recompositions; update the call to items(...) to provide a
unique key (use the game's id) so Compose can track identities and diff
efficiently — locate the items(games) lambda in GamesCarousel.kt where
FeaturedGameCard is created and change the items invocation to include key = {
game -> game.id } (or the appropriate unique id property from GameCardData) so
list updates and animations are stable.

In `@app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt`:
- Around line 150-151: Replace the two Any-typed icon properties on NavItem
(unselectedIcon and selectedIcon) with a sealed interface NavIcon and use
concrete implementations (e.g., Resource(resId: Int) and Vector(imageVector:
ImageVector)) so callers must supply either a resource id or an ImageVector
explicitly; update NavItem to take NavIcon for both unselectedIcon and
selectedIcon and refactor any creation/consumption sites to pattern-match on
NavIcon (Resource vs Vector) when rendering.

In `@app/src/main/java/com/cornellappdev/score/nav/ScoreNavigationBar.kt`:
- Around line 42-55: The code in ScoreNavigationBar.kt currently handles two
runtime icon types (Int and ImageVector) for
item.selectedIcon/item.unselectedIcon but silently does nothing for any other
type; update the implementation to either (A) add a clear else branch after the
existing checks that logs a warning via your logger (or calls a fallback Icon)
mentioning the NavItem id/title and the unexpected icon type, or (B) refactor
NavItem.selectedIcon/unselectedIcon in RootNavigation.kt to use a sealed class
(e.g., IconResource with subclasses ResourceId(val id: Int) and VectorIcon(val
vector: ImageVector)) and update ScoreNavigationBar to pattern-match on that
sealed type so unsupported cases are impossible at compile time; reference the
item variable, NavItem.selectedIcon/unselectedIcon, and the Icon composable when
making the change.

In `@app/src/main/java/com/cornellappdev/score/screen/EditProfileScreen.kt`:
- Around line 178-179: The Save button in EditProfileScreen has an empty
onClick; wire it to the screen's save flow by calling the ViewModel's
save/update method (e.g., EditProfileViewModel.saveProfile or updateProfile)
with the current editedName/editedUsername state, perform simple validation
(non-empty, username uniqueness check via the ViewModel/repository), await the
result, surface errors via the ViewModel's error state, and on success invoke
navigation back (e.g., navController.popBackStack() or provided onNavigateUp
callback). Ensure the Button's onClick references the exact state variables used
in EditProfileScreen (editedName, editedUsername) and the ViewModel method name
(saveProfile/updateProfile) so the persistence and navigation happen atomically.
- Around line 129-142: The BasicTextField usage (the one bound to variable name
with modifier Modifier.weight(1f)) has no visual affordance; replace it with an
OutlinedTextField or TextField (or add a decorationBox) to provide
focus/border/placeholder and proper padding, and ensure you forward the same
textStyle, value/onValueChange, and modifier; do the same for the other
BasicTextField instance referenced (lines ~160-173) so both fields show focus
state and editable bounds.

In `@app/src/main/java/com/cornellappdev/score/screen/ProfileScreen.kt`:
- Around line 81-84: The two GamesCarousel components in ProfileScreen (the one
at games = bookmarkedGames and the other at games = createdGames) use
placeholder onClick handlers; replace those comments by invoking the app's
navigation helper (e.g., call navigateToGameDetails(gameId) or the equivalent
navigation function used by HomeScreen/PastGamesScreen) so clicking a game
navigates to its detail screen, passing the gameId parameter through the
existing navigateToGameDetails method used elsewhere.
- Around line 51-84: Extract the duplicated header + carousel UI into a private
composable (e.g., GameSection) and replace both the "Bookmarks" block (which
currently uses bookmarkedGames and GamesCarousel) and the "Games You Might Like"
block (which uses the other games list) to call this composable; GameSection
should take title: String, games: List<GameCardData>, onClick: (String) -> Unit,
and optional modifier, render the Row with title, count ("${games.size}
Results"), chevron Icon, a Spacer, then call GamesCarousel(games = games,
onClick = onClick); update usages so bookmarkedGames and the other games list
pass through and remove the duplicated Row/Spacer/GamesCarousel blocks.
- Around line 192-207: ProfileRow currently hardcodes the display name and
handle ("Audrey Wu" and "@audreywuu"); update it to accept and render dynamic
data by wiring the Text composables to source values instead of literals. Modify
the ProfileRow (or enclosing ProfileScreen) composable to take parameters like
userName: String and userHandle: String (or read them from a ViewModel property)
and replace the hardcoded strings in the two Text calls with those
parameters/observed state so the UI reflects the real user data.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a0ea26fe-4d28-463a-b8d2-d944df5f3a18

📥 Commits

Reviewing files that changed from the base of the PR and between 254d1c7 and b9064ef.

📒 Files selected for processing (8)
  • app/build.gradle.kts
  • app/src/main/java/com/cornellappdev/score/components/GamesCarousel.kt
  • app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt
  • app/src/main/java/com/cornellappdev/score/nav/ScoreNavigationBar.kt
  • app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt
  • app/src/main/java/com/cornellappdev/score/screen/EditProfileScreen.kt
  • app/src/main/java/com/cornellappdev/score/screen/ProfileScreen.kt
  • gradle/libs.versions.toml

implementation(libs.material3)
implementation("com.google.dagger:hilt-android:2.51.1")
implementation(libs.androidx.foundation)
implementation(libs.foundation)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify what each alias resolves to in the version catalog.
fd 'libs.versions.toml|versions.toml' -t f | xargs -I{} sh -c '
  echo "=== {} ==="
  rg -n "foundation|androidx\\.foundation|compose-bom|material-icons-extended" "{}"
'

Repository: cuappdev/score-android

Length of output: 385


Remove duplicate Foundation dependency with conflicting versions

The version catalog aliases resolve libs.foundation and libs.androidx-foundation to the same module (androidx.compose.foundation:foundation) but with different versions (1.10.3 vs 1.9.4). Having both dependencies creates a version conflict risk. Keep only one alias, preferably the newer version.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/build.gradle.kts` at line 84, Remove the duplicate Foundation dependency
that causes a version conflict: delete the implementation(libs.foundation) entry
and keep the newer alias implementation(libs.androidx-foundation) (or vice versa
keep only the one that resolves to version 1.10.3). Ensure only a single
androidx.compose.foundation dependency remains in the dependencies block to
avoid mixing libs.foundation and libs.androidx-foundation.

lintChecks(libs.compose.lint.checks)
implementation(platform("com.google.firebase:firebase-bom:34.3.0"))
implementation("com.google.firebase:firebase-analytics")
implementation("androidx.compose.material:material-icons-extended:1.6.0")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm BOM usage + explicit compose versions in this file.
rg -n 'compose-bom|androidx\.compose\..*:[0-9]+\.[0-9]+(\.[0-9]+)?|material-icons-extended' app/build.gradle.kts

Repository: cuappdev/score-android

Length of output: 222


🏁 Script executed:

# Read the build.gradle.kts file around the relevant lines
sed -n '70,120p' app/build.gradle.kts | cat -n

Repository: cuappdev/score-android

Length of output: 2477


🌐 Web query:

androidx.compose compose-bom 2025.11.01 material-icons-extended version

💡 Result:

For androidx.compose:compose-bom:2025.11.01, the mapped version of:

Citations:


🌐 Web query:

androidx.compose compose-bom 2025.11.01 navigation-compose version

💡 Result:

androidx.compose:compose-bom:2025.11.01 does not manage androidx.navigation:navigation-compose (Navigation artifacts aren’t included in the Compose BOM mapping list), so there’s no “navigation-compose version” implied by that BOM. [1]

If you want a contemporary stable Navigation Compose version from around that timeframe, androidx.navigation:navigation-compose:2.9.6 was released November 5, 2025. [2] (The Compose BOM 2025.11.01 itself was published Nov 19, 2025.) [3]

Sources
[1] https://developer.android.com/develop/ui/compose/bom/bom-mapping
[2] https://developer.android.com/jetpack/androidx/releases/navigation
[3] https://mvnrepository.com/artifact/androidx.compose/compose-bom/2025.11.01


Remove explicit version from material-icons-extended to align with Compose BOM

Line 107 pins version 1.6.0 while the Compose BOM on Line 75 (2025.11.01) specifies 1.7.8. This explicit pin forces a downgrade and breaks version alignment.

Proposed fix
-    implementation("androidx.compose.material:material-icons-extended:1.6.0")
+    implementation("androidx.compose.material:material-icons-extended")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
implementation("androidx.compose.material:material-icons-extended:1.6.0")
implementation("androidx.compose.material:material-icons-extended")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/build.gradle.kts` at line 107, Remove the explicit version suffix from
the implementation dependency for
"androidx.compose.material:material-icons-extended:1.6.0" so it inherits the
version from the Compose BOM (the compose BOM declaration in the build script),
preventing the BOM from being downgraded; locate the dependency string
"implementation(\"androidx.compose.material:material-icons-extended:1.6.0\")"
and change it to the form without a version so it aligns with the BOM-managed
Compose version.

Comment on lines +61 to +68
Icon(
imageVector = Icons.Outlined.ChevronLeft,
contentDescription = "Back",
modifier = Modifier
.align(Alignment.CenterStart)
.size(24.dp)
.clickable { onBackClick() }
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Back button touch target may be too small for accessibility.

The back icon is 24.dp with no additional padding in the clickable area. Android accessibility guidelines recommend a minimum touch target of 48.dp. Consider:

♿ Suggested fix
             Icon(
                 imageVector = Icons.Outlined.ChevronLeft,
                 contentDescription = "Back",
                 modifier = Modifier
                     .align(Alignment.CenterStart)
                     .size(24.dp)
-                    .clickable { onBackClick() }
+                    .clickable(
+                        onClick = { onBackClick() },
+                        interactionSource = remember { MutableInteractionSource() },
+                        indication = null
+                    )
+                    .padding(12.dp) // Expands touch target to 48dp
             )

Or use IconButton which handles touch targets automatically.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Icon(
imageVector = Icons.Outlined.ChevronLeft,
contentDescription = "Back",
modifier = Modifier
.align(Alignment.CenterStart)
.size(24.dp)
.clickable { onBackClick() }
)
Icon(
imageVector = Icons.Outlined.ChevronLeft,
contentDescription = "Back",
modifier = Modifier
.align(Alignment.CenterStart)
.size(24.dp)
.clickable(
onClick = { onBackClick() },
interactionSource = remember { MutableInteractionSource() },
indication = null
)
.padding(12.dp) // Expands touch target to 48dp
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/screen/EditProfileScreen.kt` around
lines 61 - 68, The back Icon in EditProfileScreen (Icons.Outlined.ChevronLeft)
uses a 24.dp visual size and a clickable modifier, yielding a touch target
smaller than the 48.dp accessibility recommendation; replace the plain Icon
clickable with an IconButton (or wrap the Icon in a Box with a minimum touch
target) so the clickable area meets 48.dp, keep the visual icon size at 24.dp
(e.g., set Icon size to 24.dp while the IconButton/Box provides the larger touch
area) and call onBackClick() from the IconButton's onClick to preserve behavior.

runtime = "1.9.4"
ui = "1.9.4"
foundation = "1.9.4"
foundationVersion = "1.10.3"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Catalog entries involved =="
rg -n -C2 '^(runtime|ui|foundation|foundationVersion)\s*=|^androidx-foundation\s*=|^foundation\s*=' gradle/libs.versions.toml

echo
echo "== Where foundation aliases are used =="
fd -t f 'build\.gradle(\.kts)?$' | xargs -r rg -n -C2 'libs\.(androidx\.foundation|foundation)\b'

echo
echo "== Compose dependency strategy (BOM vs direct versions) =="
fd -t f 'build\.gradle(\.kts)?$' | xargs -r rg -n -C2 'compose-bom|platform\(|androidx\.compose'

Repository: cuappdev/score-android

Length of output: 2684


Both Compose foundation aliases with different versions are active—remove one to avoid duplicate classpath and version conflict.

Lines 22, 38–39 create two aliases (androidx-foundation → 1.9.4 and foundation → 1.10.3) for the same artifact (androidx.compose.foundation:foundation), and both are imported at lines 83–84 in app/build.gradle.kts. This will cause version conflicts on the classpath or unpredictable resolution at runtime. Remove one alias and consolidate to a single version reference. Since the build already uses Compose BOM (androidx.compose:compose-bom:2025.11.01), verify the intended foundation version aligns with or is intentionally decoupled from the BOM.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gradle/libs.versions.toml` at line 22, You have two duplicate aliases for the
same artifact—androidx-foundation and foundation—pointing to different versions;
remove one alias from libs.versions.toml and update the build script imports to
use only the remaining alias (or switch the build to rely on the Compose BOM
instead of an explicit alias); ensure the kept alias/version for
androidx.compose.foundation matches the intended BOM alignment or is
intentionally decoupled so you don’t get conflicting versions on the classpath.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants