Skip to content

profile page and the entry point#57

Open
durualayli wants to merge 1 commit intomainfrom
Duru/profile-page
Open

profile page and the entry point#57
durualayli wants to merge 1 commit intomainfrom
Duru/profile-page

Conversation

@durualayli
Copy link
Contributor

@durualayli durualayli commented Mar 18, 2026

ScreenRecording_03-18-2026.16-18-40_1.1.1.1.1.mp4
  • Added the profile view entry point to all of the main views (however, the way I did it felt a little uncomfortable, so if you guys have any other suggestions, that would be great!)
  • The profile page UI with the dummy games you might like section and the bookmarks section
  • Edit profile page view where user can change the name, username, and the profile image (specific image picker view)
  • For now, user data saved in UserDefaults however, later may use backend

Next steps:

  • Notifications button
  • User login / account creation
  • Bookmarks page and games you might like

Summary by CodeRabbit

Release Notes

  • New Features

    • User profile management: create and edit profile with name, username, and profile image selection from a gallery of predefined avatars.
    • Enhanced navigation with profile access buttons integrated across app views.
    • Profile UI with dedicated sections for bookmarks and recommended games.
  • Style

    • Updated visual assets and color palette for improved app consistency.

@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

📝 Walkthrough

Walkthrough

This PR introduces a user profile feature to the iOS app. It adds a User model, ProfileViewModel for state management, a TopHeader component used across views, and a complete ProfileView with editing capabilities. Existing views are updated with showProfile bindings to enable navigation to the profile. Numerous image assets are added for profile pictures and UI elements.

Changes

Cohort / File(s) Summary
Project Configuration
score-ios.xcodeproj/project.pbxproj
Updated development team ID from W7U2WA4D54 to H5ZTDCQ89H; added build file references and group membership for User.swift, ProfileView.swift, TopHeader.swift, and ProfileViewModel.swift.
Core Models & ViewModels
score-ios/Models/User.swift, score-ios/ViewModels/ProfileViewModel.swift
Added User struct with name, username, and profileImage properties. Added ProfileViewModel as an ObservableObject with singleton shared instance, @Published user property, and saveUser method that persists to UserDefaults.
UI Components
score-ios/Views/DetailedViews/TopHeader.swift, score-ios/Views/MainViews/ProfileView.swift
Introduced TopHeader component with title and profile/notification buttons. Added comprehensive ProfileView with profile display, edit modal, and image selection grid; integrates with ProfileViewModel for data management.
View Updates
score-ios/Views/ListViews/CarouselView.swift, score-ios/Views/ListViews/HighlightView.swift, score-ios/Views/ListViews/PastGamesView.swift, score-ios/Views/ListViews/UpcomingGamesView.swift, score-ios/Views/MainViews/MainTabView.swift
Added showProfile binding across carousel and list views; replaced static headers with TopHeader in HighlightView; added navigationDestination and showProfile state management in MainTabView for profile navigation.
Assets & Constants
score-ios/Resources/Assets.xcassets/*, score-ios/Utils/Constants.swift
Added image asset manifests for profile pictures (profile0-11), icons (Arrowhead, BookmarkGame, check, cross, dehaze, notifications, profile); added primary_gray color constant.

Sequence Diagram

sequenceDiagram
    actor User
    participant MainTabView
    participant ProfileView
    participant ProfileViewModel
    participant UserDefaults

    User->>MainTabView: Tap profile button
    MainTabView->>MainTabView: Set showProfile = true
    MainTabView->>ProfileView: Navigate (navigationDestination)
    ProfileView->>ProfileViewModel: Read shared.user
    ProfileViewModel->>UserDefaults: Load name, username, profileImage
    ProfileViewModel-->>ProfileView: Return User object

    User->>ProfileView: Tap "Edit profile"
    ProfileView->>ProfileView: Show editProfileView modal

    User->>ProfileView: Select profile image from grid
    User->>ProfileView: Update name/username fields
    User->>ProfileView: Tap Save

    ProfileView->>ProfileViewModel: saveUser(name, username, profileImage)
    ProfileViewModel->>UserDefaults: Persist updated values
    ProfileViewModel->>ProfileViewModel: Update `@Published` user
    ProfileView->>ProfileView: Dismiss edit modal & refresh display
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Poem

🐰 A profile page hops into view,
With editable fields and images too!
TopHeaders guide the way so clear,
UserDefaults keeps memories here.
Now users can show who they are—
A feature as bright as a star! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'profile page and the entry point' accurately summarizes the main changes: implementation of a profile page and its integration as an entry point across main views.

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

Important

Merge conflicts detected (Beta)

  • Resolve merge conflict in branch Duru/profile-page
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch Duru/profile-page
📝 Coding Plan
  • ❌ Error while generating coding plan for human review comments - (🔄 Check again to try again)

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

Tip

CodeRabbit can use OpenGrep to find security vulnerabilities and bugs across 17+ programming languages.

OpenGrep is compatible with Semgrep configurations. Add an opengrep.yml or semgrep.yml configuration file to your project to enable OpenGrep analysis.

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: 3

🧹 Nitpick comments (9)
score-ios/Resources/Assets.xcassets/cross.imageset/Contents.json (1)

8-15: Provide explicit 2x/3x image files for this bitmap asset.

Line 10 and Line 14 declare 2x/3x entries without filenames, so this set can fall back to scaling the 1x image on retina devices.

Suggested manifest update
   {
+    "filename" : "Group 8@2x.png",
     "idiom" : "universal",
     "scale" : "2x"
   },
   {
+    "filename" : "Group 8@3x.png",
     "idiom" : "universal",
     "scale" : "3x"
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@score-ios/Resources/Assets.xcassets/cross.imageset/Contents.json` around
lines 8 - 15, The asset's Contents.json declares "scale" entries for "2x" and
"3x" without "filename" keys so iOS will fallback to scaling the 1x bitmap; add
explicit 2x and 3x image files to the asset and update the cross.imageset
Contents.json entries to include the corresponding "filename" values (for
example cross@2x.png and cross@3x.png) for the objects with "scale":"2x" and
"scale":"3x", and make sure those image files are added to the asset catalog
bundle.
score-ios/Resources/Assets.xcassets/BookmarkGame.imageset/Contents.json (1)

4-4: Consider renaming asset file for clarity.

The filename image 6.png is non-descriptive and contains a space. Consider renaming it to something more meaningful like BookmarkGame.png or bookmark-game.png for better maintainability and consistency with other asset naming conventions.

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

In `@score-ios/Resources/Assets.xcassets/BookmarkGame.imageset/Contents.json` at
line 4, The asset file currently named "image 6.png" in BookmarkGame.imageset is
non-descriptive and contains a space; rename the file to a clear, consistent
name (for example BookmarkGame.png or bookmark-game.png), update the "filename"
value in Contents.json to match the new filename, and verify/update any code or
storyboard references that load this asset so they point to the renamed
file/asset name.
score-ios/Models/User.swift (1)

8-12: Consider adding Codable conformance for persistence.

Since User data is saved to UserDefaults (per PR description), adding Codable conformance would simplify serialization. Also consider Equatable for comparisons.

♻️ Proposed enhancement
-struct User {
+struct User: Codable, Equatable {
     var name: String
     var username: String
     var profileImage: String
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@score-ios/Models/User.swift` around lines 8 - 12, The User model currently
lacks Codable/Equatable conformance which makes saving to UserDefaults and
comparing instances cumbersome; update the struct User to conform to Codable and
Equatable, and switch the persistence code that writes/reads users to use
JSONEncoder/JSONDecoder (or PropertyListEncoder/Decoder) so serialization is
automatic and type-safe; ensure any custom key naming is handled via a
CodingKeys enum inside User if needed and update any equality assumptions to
rely on the synthesized Equatable implementation.
score-ios/Resources/Assets.xcassets/Arrowhead.imageset/Contents.json (1)

1-21: Missing 2x and 3x image assets.

Only the 1x variant has a filename specified. Consider providing 2x and 3x assets to ensure crisp rendering on Retina displays, or use a vector PDF/SVG asset that scales automatically.

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

In `@score-ios/Resources/Assets.xcassets/Arrowhead.imageset/Contents.json` around
lines 1 - 21, Contents.json for Arrowhead.imageset only references the 1x bitmap
(Arrowhead.png) and omits filenames for the 2x and 3x entries, causing missing
Retina assets; update the Arrowhead.imageset Contents.json so the "images" array
includes valid "filename" entries for the 2x and 3x variants (e.g.,
Arrowhead@2x.png and Arrowhead@3x.png) or replace the bitmaps with a single
vector asset (PDF/SVG) and adjust the entries accordingly so Arrowhead.imageset
provides proper scaled assets for Retina displays.
score-ios/Resources/Assets.xcassets/profile1.imageset/Contents.json (1)

4-4: Non-descriptive filename from design export.

The filename Ellipse 18.png appears to be a raw export from a design tool. Consider renaming to something descriptive like profile1.png or profile-avatar-1.png for better maintainability.

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

In `@score-ios/Resources/Assets.xcassets/profile1.imageset/Contents.json` at line
4, Rename the non-descriptive asset file named "Ellipse 18.png" to a clear,
maintainable name (e.g., "profile1.png" or "profile-avatar-1.png") and update
the corresponding "filename" value in Contents.json to match that new filename;
also update any code or storyboard references that load this asset (image sets
or image literals) to use the new name ("profile1" or "profile-avatar-1") so the
asset bundle and runtime lookups remain consistent.
score-ios/Views/MainViews/ProfileView.swift (1)

13-13: Make profileViewModel private to follow SwiftUI best practices.

SwiftUI state properties (@StateObject, @State, @ObservedObject) should be marked private to prevent external mutation that could cause unexpected behavior.

♻️ Proposed fix
-@StateObject var profileViewModel = ProfileViewModel.shared
+@StateObject private var profileViewModel = ProfileViewModel.shared
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@score-ios/Views/MainViews/ProfileView.swift` at line 13, Make the
`@StateObject` property profileViewModel private to follow SwiftUI best practices:
change the declaration of profileViewModel (currently "@StateObject var
profileViewModel = ProfileViewModel.shared") to a private `@StateObject` so
external views cannot mutate it (e.g., use "private `@StateObject`" for the
profileViewModel property referencing ProfileViewModel.shared).
score-ios/ViewModels/ProfileViewModel.swift (2)

14-14: Consider making init() private to enforce singleton usage.

The singleton pattern with static let shared is good, but the init() is implicitly internal, allowing other code to create additional instances. Making it private would enforce that only shared is used.

♻️ Proposed fix to enforce singleton
 static let shared = ProfileViewModel()
 
 // MARK: - Functions
-init() {
+private init() {
     let name = UserDefaults.standard.string(forKey: "name") ?? "Name"
     let username = UserDefaults.standard.string(forKey: "username") ?? "username"
     let profileImage = UserDefaults.standard.string(forKey: "profileImage") ?? "profile0"
     
     self.user = User(name: name, username: username, profileImage: profileImage)
 }

Also applies to: 17-23

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

In `@score-ios/ViewModels/ProfileViewModel.swift` at line 14, The class exposes a
public initializer allowing multiple instances despite having a singleton
`static let shared`; make the initializer private to enforce singleton usage by
changing `init()` in `ProfileViewModel` to `private init()`, ensuring all
construction goes through the `shared` property and preventing external
instantiation.

18-20: Consider extracting UserDefaults keys to constants.

The same string keys are used in both init() and saveUser(). Extracting them to constants would prevent typos and make updates easier.

♻️ Proposed refactor
 class ProfileViewModel: ObservableObject {
+    private enum Keys {
+        static let name = "name"
+        static let username = "username"
+        static let profileImage = "profileImage"
+    }
+    
     `@Published` var user: User
     
     static let shared = ProfileViewModel()
     
     // MARK: - Functions
-    init() {
-        let name = UserDefaults.standard.string(forKey: "name") ?? "Name"
-        let username = UserDefaults.standard.string(forKey: "username") ?? "username"
-        let profileImage = UserDefaults.standard.string(forKey: "profileImage") ?? "profile0"
+    private init() {
+        let name = UserDefaults.standard.string(forKey: Keys.name) ?? "Name"
+        let username = UserDefaults.standard.string(forKey: Keys.username) ?? "username"
+        let profileImage = UserDefaults.standard.string(forKey: Keys.profileImage) ?? "profile0"
         
         self.user = User(name: name, username: username, profileImage: profileImage)
     }
     
     func saveUser(name: String, username: String, profileImage: String) {
         user.name = name
         user.username = username
         user.profileImage = profileImage
         
-        UserDefaults.standard.set(name, forKey: "name")
-        UserDefaults.standard.set(username, forKey: "username")
-        UserDefaults.standard.set(profileImage, forKey: "profileImage")
+        UserDefaults.standard.set(name, forKey: Keys.name)
+        UserDefaults.standard.set(username, forKey: Keys.username)
+        UserDefaults.standard.set(profileImage, forKey: Keys.profileImage)
     }
 }

Also applies to: 30-32

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

In `@score-ios/ViewModels/ProfileViewModel.swift` around lines 18 - 20, Extract
the repeated UserDefaults keys ("name", "username", "profileImage") into single
constants and use those constants in both init() and saveUser(); e.g., add a
private static constant or a small enum (like
UserDefaultsKeys.name/username/profileImage) inside ProfileViewModel and replace
all literal string usages in init() and saveUser() with those constants to avoid
duplication and typos.
score-ios/Views/DetailedViews/TopHeader.swift (1)

21-35: Consider adding accessibility labels to the buttons.

The buttons use image-only labels which may not be accessible to VoiceOver users. Adding accessibility labels would improve the user experience for assistive technology users.

♿ Proposed accessibility improvement
 Button {
     // notifications
 } label: {
     Image("notifications")
         .resizable()
         .frame(width: 36, height: 36)
 }
+.accessibilityLabel("Notifications")

 Button {
     onProfileTap()
 } label: {
     Image("profile")
         .resizable()
         .frame(width: 28, height: 28)
 }
+.accessibilityLabel("Profile")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@score-ios/Views/DetailedViews/TopHeader.swift` around lines 21 - 35, The
image-only Buttons for notifications and profile lack accessibility labels;
update the Button views that use Image("notifications") and Image("profile")
(the Button that currently calls onProfileTap()) to add descriptive
accessibility labels (e.g., .accessibilityLabel("Notifications") and
.accessibilityLabel("Profile")) and, if helpful for UI tests, an
accessibilityIdentifier; ensure the labels are concise and match the button
purpose so VoiceOver users can understand and invoke the controls.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@score-ios/Resources/Assets.xcassets/notifications.imageset/Contents.json`:
- Around line 1-21: The Contents.json for the notifications imageset only
references the 1x asset "line-md_bell.png" so Retina devices will upscale it;
add properly scaled 2x and 3x PNGs (e.g., "line-md_bell@2x.png" and
"line-md_bell@3x.png"), update the images array entries to include those
filenames with "scale": "2x"/"3x" for the same idiom, and repeat this fix for
the other affected imagesets (profile3, profile6, profile7, profile8, profile9,
profile11, dehaze) so each set contains 1x/2x/3x filename entries in their
Contents.json files.

In `@score-ios/Views/MainViews/ProfileView.swift`:
- Around line 311-317: The image-chooser Button currently calls
profileViewModel.saveUser(name:editedName, username:editedUsername,
profileImage:editedImage) and toggles isSheet, causing duplicate/overlapping
saves with the edit-profile Save button; change the image chooser to either (A)
persist only the image by calling a dedicated method like
profileViewModel.saveProfileImage(profileImage: editedImage) (create that method
if missing) and then dismiss via isSheet.toggle(), or (B) remove the save call
entirely so the Button only updates editedImage and dismisses (isSheet.toggle())
and let the edit-profile Save button call saveUser(...) once; update the Button
action accordingly to use the selected approach.
- Around line 203-206: The profile image view is always showing
profileViewModel.user.profileImage so it doesn't reflect the user's current
selection (editedImage); change the Image source to use editedImage when
available (fallback to profileViewModel.user.profileImage) so the view updates
immediately after selection—update the Image in the VStack to read from
editedImage (or editedImage.flatMap / optional check) instead of directly from
profileViewModel.user.profileImage and ensure editedImage is kept in sync (it is
already set in the image chooser), so the chosen image appears immediately.

---

Nitpick comments:
In `@score-ios/Models/User.swift`:
- Around line 8-12: The User model currently lacks Codable/Equatable conformance
which makes saving to UserDefaults and comparing instances cumbersome; update
the struct User to conform to Codable and Equatable, and switch the persistence
code that writes/reads users to use JSONEncoder/JSONDecoder (or
PropertyListEncoder/Decoder) so serialization is automatic and type-safe; ensure
any custom key naming is handled via a CodingKeys enum inside User if needed and
update any equality assumptions to rely on the synthesized Equatable
implementation.

In `@score-ios/Resources/Assets.xcassets/Arrowhead.imageset/Contents.json`:
- Around line 1-21: Contents.json for Arrowhead.imageset only references the 1x
bitmap (Arrowhead.png) and omits filenames for the 2x and 3x entries, causing
missing Retina assets; update the Arrowhead.imageset Contents.json so the
"images" array includes valid "filename" entries for the 2x and 3x variants
(e.g., Arrowhead@2x.png and Arrowhead@3x.png) or replace the bitmaps with a
single vector asset (PDF/SVG) and adjust the entries accordingly so
Arrowhead.imageset provides proper scaled assets for Retina displays.

In `@score-ios/Resources/Assets.xcassets/BookmarkGame.imageset/Contents.json`:
- Line 4: The asset file currently named "image 6.png" in BookmarkGame.imageset
is non-descriptive and contains a space; rename the file to a clear, consistent
name (for example BookmarkGame.png or bookmark-game.png), update the "filename"
value in Contents.json to match the new filename, and verify/update any code or
storyboard references that load this asset so they point to the renamed
file/asset name.

In `@score-ios/Resources/Assets.xcassets/cross.imageset/Contents.json`:
- Around line 8-15: The asset's Contents.json declares "scale" entries for "2x"
and "3x" without "filename" keys so iOS will fallback to scaling the 1x bitmap;
add explicit 2x and 3x image files to the asset and update the cross.imageset
Contents.json entries to include the corresponding "filename" values (for
example cross@2x.png and cross@3x.png) for the objects with "scale":"2x" and
"scale":"3x", and make sure those image files are added to the asset catalog
bundle.

In `@score-ios/Resources/Assets.xcassets/profile1.imageset/Contents.json`:
- Line 4: Rename the non-descriptive asset file named "Ellipse 18.png" to a
clear, maintainable name (e.g., "profile1.png" or "profile-avatar-1.png") and
update the corresponding "filename" value in Contents.json to match that new
filename; also update any code or storyboard references that load this asset
(image sets or image literals) to use the new name ("profile1" or
"profile-avatar-1") so the asset bundle and runtime lookups remain consistent.

In `@score-ios/ViewModels/ProfileViewModel.swift`:
- Line 14: The class exposes a public initializer allowing multiple instances
despite having a singleton `static let shared`; make the initializer private to
enforce singleton usage by changing `init()` in `ProfileViewModel` to `private
init()`, ensuring all construction goes through the `shared` property and
preventing external instantiation.
- Around line 18-20: Extract the repeated UserDefaults keys ("name", "username",
"profileImage") into single constants and use those constants in both init() and
saveUser(); e.g., add a private static constant or a small enum (like
UserDefaultsKeys.name/username/profileImage) inside ProfileViewModel and replace
all literal string usages in init() and saveUser() with those constants to avoid
duplication and typos.

In `@score-ios/Views/DetailedViews/TopHeader.swift`:
- Around line 21-35: The image-only Buttons for notifications and profile lack
accessibility labels; update the Button views that use Image("notifications")
and Image("profile") (the Button that currently calls onProfileTap()) to add
descriptive accessibility labels (e.g., .accessibilityLabel("Notifications") and
.accessibilityLabel("Profile")) and, if helpful for UI tests, an
accessibilityIdentifier; ensure the labels are concise and match the button
purpose so VoiceOver users can understand and invoke the controls.

In `@score-ios/Views/MainViews/ProfileView.swift`:
- Line 13: Make the `@StateObject` property profileViewModel private to follow
SwiftUI best practices: change the declaration of profileViewModel (currently
"@StateObject var profileViewModel = ProfileViewModel.shared") to a private
`@StateObject` so external views cannot mutate it (e.g., use "private
`@StateObject`" for the profileViewModel property referencing
ProfileViewModel.shared).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c0d58cc3-f11e-4791-bd50-a904aa07d772

📥 Commits

Reviewing files that changed from the base of the PR and between fe23b97 and 3214537.

⛔ Files ignored due to path filters (19)
  • score-ios/Resources/Assets.xcassets/Arrowhead.imageset/Arrowhead.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/BookmarkGame.imageset/image 6.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/check.imageset/check.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/cross.imageset/Group 8.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/dehaze.imageset/dehaze.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/notifications.imageset/line-md_bell.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile.imageset/profile (1).png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile0.imageset/image.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile1.imageset/Ellipse 18.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile10.imageset/Ellipse 15.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile11.imageset/Ellipse 19.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile2.imageset/Ellipse 9.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile3.imageset/Ellipse 10.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile4.imageset/Ellipse 11.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile5.imageset/Ellipse 13 (1).png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile6.imageset/Ellipse 14.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile7.imageset/Ellipse 16.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile8.imageset/Ellipse 17.png is excluded by !**/*.png
  • score-ios/Resources/Assets.xcassets/profile9.imageset/Ellipse 12.png is excluded by !**/*.png
📒 Files selected for processing (30)
  • score-ios.xcodeproj/project.pbxproj
  • score-ios/Models/User.swift
  • score-ios/Resources/Assets.xcassets/Arrowhead.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/BookmarkGame.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/check.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/cross.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/dehaze.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/notifications.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile0.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile1.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile10.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile11.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile2.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile3.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile4.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile5.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile6.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile7.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile8.imageset/Contents.json
  • score-ios/Resources/Assets.xcassets/profile9.imageset/Contents.json
  • score-ios/Utils/Constants.swift
  • score-ios/ViewModels/ProfileViewModel.swift
  • score-ios/Views/DetailedViews/TopHeader.swift
  • score-ios/Views/ListViews/CarouselView.swift
  • score-ios/Views/ListViews/HighlightView.swift
  • score-ios/Views/ListViews/PastGamesView.swift
  • score-ios/Views/ListViews/UpcomingGamesView.swift
  • score-ios/Views/MainViews/MainTabView.swift
  • score-ios/Views/MainViews/ProfileView.swift

Comment on lines +1 to +21
{
"images" : [
{
"filename" : "line-md_bell.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
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

Missing 2x and 3x image assets.

Only the 1x image (line-md_bell.png) is provided. Without 2x and 3x variants, iOS will upscale the 1x image on Retina displays, resulting in blurry visuals. Consider adding appropriately scaled images for better display quality.

This observation applies to all profile image sets and other asset catalogs in this PR that follow the same pattern (profile3, profile6, profile7, profile8, profile9, profile11, dehaze).

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

In `@score-ios/Resources/Assets.xcassets/notifications.imageset/Contents.json`
around lines 1 - 21, The Contents.json for the notifications imageset only
references the 1x asset "line-md_bell.png" so Retina devices will upscale it;
add properly scaled 2x and 3x PNGs (e.g., "line-md_bell@2x.png" and
"line-md_bell@3x.png"), update the images array entries to include those
filenames with "scale": "2x"/"3x" for the same idiom, and repeat this fix for
the other affected imagesets (profile3, profile6, profile7, profile8, profile9,
profile11, dehaze) so each set contains 1x/2x/3x filename entries in their
Contents.json files.

Comment on lines +203 to +206
VStack (spacing: 16){
Image (profileViewModel.user.profileImage)
.resizable()
.frame(width: 120,height: 120)
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

Bug: Edit profile view shows persisted image instead of the selected image.

When the user selects a new profile image in the image chooser sheet, editedImage is updated (line 296), but this view still displays profileViewModel.user.profileImage. The user won't see their selection reflected until after saving.

🐛 Proposed fix
 VStack (spacing: 16){
-    Image (profileViewModel.user.profileImage)
+    Image (editedImage.isEmpty ? profileViewModel.user.profileImage : editedImage)
         .resizable()
         .frame(width: 120,height: 120)

Alternatively, since editedImage is initialized from profileViewModel.user.profileImage on appear (line 265), you can simply use:

-    Image (profileViewModel.user.profileImage)
+    Image (editedImage)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@score-ios/Views/MainViews/ProfileView.swift` around lines 203 - 206, The
profile image view is always showing profileViewModel.user.profileImage so it
doesn't reflect the user's current selection (editedImage); change the Image
source to use editedImage when available (fallback to
profileViewModel.user.profileImage) so the view updates immediately after
selection—update the Image in the VStack to read from editedImage (or
editedImage.flatMap / optional check) instead of directly from
profileViewModel.user.profileImage and ensure editedImage is kept in sync (it is
already set in the image chooser), so the chosen image appears immediately.

Comment on lines +311 to +317
Button(action: {
profileViewModel.saveUser(
name: editedName,
username: editedUsername,
profileImage: editedImage
)
isSheet.toggle()
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

Two Save buttons may cause unexpected behavior.

The image chooser's Save button (here) saves name, username, and image together, while the edit profile view also has its own Save button (line 244-250). If a user modifies their name, then opens the image picker and clicks Save, all changes are persisted - which may or may not be the intended behavior.

Consider either:

  1. Having the image chooser Save only persist the image change, or
  2. Removing the Save button from the image chooser and just having it dismiss on selection
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@score-ios/Views/MainViews/ProfileView.swift` around lines 311 - 317, The
image-chooser Button currently calls profileViewModel.saveUser(name:editedName,
username:editedUsername, profileImage:editedImage) and toggles isSheet, causing
duplicate/overlapping saves with the edit-profile Save button; change the image
chooser to either (A) persist only the image by calling a dedicated method like
profileViewModel.saveProfileImage(profileImage: editedImage) (create that method
if missing) and then dismiss via isSheet.toggle(), or (B) remove the save call
entirely so the Button only updates editedImage and dismisses (isSheet.toggle())
and let the edit-profile Save button call saveUser(...) once; update the Button
action accordingly to use the selected approach.

@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

No open human review comments were found in this PR to create a plan for.

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.

1 participant