Description:
This issue addresses two related UI improvements: loading the user's actual Codeforces avatar on the Profile screen, and creating a shared EmptyStateView component to standardize how empty, error, and loading states are presented across all screens.
Part A: Profile Avatar
Current Behavior:
The profile header uses a placeholder SF Symbol (person.fill), even though:
- The Codeforces
user.info API returns an avatar URL (titlePhoto / avatar field).
SDWebImageSwiftUI is already imported in ProfileView.swift but is never used.
Feature Requirements:
- Add
avatar and titlePhoto fields to the CodeforcesUser model in ProfileModels.swift.
- Replace the placeholder icon in
profileHeader() with a WebImage from SDWebImageSwiftUI that loads the actual avatar.
- Provide a fallback to the existing SF Symbol if the image URL is
nil or fails to load.
- Retain the existing circular shape with gradient border styling.
Note: Codeforces avatar URLs are often protocol-relative (e.g., //userpic.codeforces.org/...). Prepend https: before using them.
Part B: Reusable Empty State Component
Current Behavior:
Empty, error, and loading states are handled inconsistently across the app:
| Screen |
Implementation |
ContestListView |
Plain ProgressView() with no empty results or error state |
ProblemListView |
Custom VStack with icon and retry button |
ProfileView |
Raw error text string |
ProblemSubmissionsView |
ContentUnavailableView (iOS 17+ only) |
Feature Requirements:
- Create a reusable
EmptyStateView in CForge/Views/Common/EmptyStateView.swift with configurable icon, title, subtitle, and optional action button.
- Style it with the app's neon dark theme (gradient icon,
.textPrimary title, gradient action button).
- Replace all inconsistent empty/error/loading state implementations across
ContestListView, ProblemListView, ProfileView, and ProblemSubmissionsView with the shared component.
Steps to Implement:
Part A:
- Add
avatar: String? and titlePhoto: String? to CodeforcesUser in ProfileModels.swift.
- In
ProfileView.profileHeader(), replace the SF Symbol with WebImage(url:) from SDWebImageSwiftUI.
- Add a
.placeholder { ... } modifier for fallback.
- Ensure the avatar retains circular clipping and the gradient border overlay.
Part B:
- Create
CForge/Views/Common/EmptyStateView.swift with a configurable initializer.
- Apply the neon theme: gradient-colored SF Symbol icon, proper text hierarchy, optional neon-styled retry button.
- Replace empty/error states in
ContestListView, ProblemListView, ProfileView, and ProblemSubmissionsView.
- Optionally update the existing
LoadingView.swift to match the new design.
Key Files:
| Action |
File |
| MODIFY |
CForge/Views/Profile/ProfileModels.swift |
| MODIFY |
CForge/Views/Profile/ProfileView.swift |
| CREATE |
CForge/Views/Common/EmptyStateView.swift |
| MODIFY |
CForge/Views/Contest/ContestListView.swift |
| MODIFY |
CForge/Views/Problem/ProblemListView.swift |
| MODIFY |
CForge/Views/Problem/ProblemSubmissionsView.swift |
Expected Outcome:
- The Profile screen displays the user's actual Codeforces avatar with a graceful fallback.
- All screens use the shared
EmptyStateView for consistent empty, error, and loading presentations.
- The UI across the entire app feels polished and unified.
Description:
This issue addresses two related UI improvements: loading the user's actual Codeforces avatar on the Profile screen, and creating a shared
EmptyStateViewcomponent to standardize how empty, error, and loading states are presented across all screens.Part A: Profile Avatar
Current Behavior:
The profile header uses a placeholder SF Symbol (
person.fill), even though:user.infoAPI returns an avatar URL (titlePhoto/avatarfield).SDWebImageSwiftUIis already imported inProfileView.swiftbut is never used.Feature Requirements:
avatarandtitlePhotofields to theCodeforcesUsermodel inProfileModels.swift.profileHeader()with aWebImagefrom SDWebImageSwiftUI that loads the actual avatar.nilor fails to load.Part B: Reusable Empty State Component
Current Behavior:
Empty, error, and loading states are handled inconsistently across the app:
ContestListViewProgressView()with no empty results or error stateProblemListViewVStackwith icon and retry buttonProfileViewProblemSubmissionsViewContentUnavailableView(iOS 17+ only)Feature Requirements:
EmptyStateViewinCForge/Views/Common/EmptyStateView.swiftwith configurable icon, title, subtitle, and optional action button..textPrimarytitle, gradient action button).ContestListView,ProblemListView,ProfileView, andProblemSubmissionsViewwith the shared component.Steps to Implement:
Part A:
avatar: String?andtitlePhoto: String?toCodeforcesUserinProfileModels.swift.ProfileView.profileHeader(), replace the SF Symbol withWebImage(url:)from SDWebImageSwiftUI..placeholder { ... }modifier for fallback.Part B:
CForge/Views/Common/EmptyStateView.swiftwith a configurable initializer.ContestListView,ProblemListView,ProfileView, andProblemSubmissionsView.LoadingView.swiftto match the new design.Key Files:
CForge/Views/Profile/ProfileModels.swiftCForge/Views/Profile/ProfileView.swiftCForge/Views/Common/EmptyStateView.swiftCForge/Views/Contest/ContestListView.swiftCForge/Views/Problem/ProblemListView.swiftCForge/Views/Problem/ProblemSubmissionsView.swiftExpected Outcome:
EmptyStateViewfor consistent empty, error, and loading presentations.