Update ProfileScreen to properly use ProfileUiState and display Projects count#10
Update ProfileScreen to properly use ProfileUiState and display Projects count#10TheRealAshik wants to merge 23 commits into
Conversation
…hardcoding - Added `HomeScreen` matching the prototype with four sections: My Work, Favorites, Shortcuts, Recent. - Defined `HomeViewModel` and `HomeUiState` providing placeholder data via `StateFlow`. - Created `strings.xml` for all strings and `Dimens.kt` for spacing/size tokens. - Updated `MainScreen` to wire `HomeScreen` into the Home tab with active (filled) and inactive (outlined) icons. - Updated `AGENTS.md` with strict No Hardcoding Policy.
- Create strings.xml to house string resources - Create `RepositoryDetailScreen` and `RepositoryDetailUiState` matching prototypes - Create `PullRequestListScreen` and `PullRequestListUiState` - Create `CompareBranchSheet` ModalBottomSheet - Add `Dimens.kt` to extract UI dimensions and enforce "no hardcoding" rules - Ensure stateless screen implementations
This commit introduces the initial UI implementation for the Inbox and Explore tabs. It follows strict rules of zero hardcoding: - Created strings.xml for all texts and mock texts. - Created Dimensions.kt object for layout sizes. - Utilized MaterialTheme tokens for colors, typography, and shapes. Screens are wired up to MainScreen's bottom navigation, correctly switching between them. Mock data is exposed through StateFlow in ViewModels (InboxViewModel and ExploreViewModel). UI matches the given design prototype.
- Created stateless Composable screens `ProfileScreen` and `RepositoryListScreen`. - Created ViewModels (`ProfileViewModel` and `RepositoryListViewModel`) exposing mock UI states with `StateFlow`. - Created `strings.xml` to hold all UI strings and mock data strings. - Enforced zero-hardcoding policy by using `MaterialTheme` exclusively for tokens. - Extracted all dimensions into a new `Dimens.kt` object. - Replaced hardcoded strings and colors in MainScreen and ProfileScreen with extracted tokens. - Added crossfade navigation logic mapped from main home screen avatar to profile and then repo list.
…ount sheet - Created ViewModels and States for settings, code options, and notification options - Created Compose Multiplatform SettingsScreen, CodeOptionsScreen, NotificationOptionsScreen, and AccountsSheet - Applied Material3 and MaterialTheme styling and strict no-hardcoding constants using a SettingsTokens class and strings.xml resource values
- GitHubApiClient: add GitHubRepo, GitHubOrg, GitHubNotification models and getUserRepos, getUserOrgs, getNotifications, getStarredRepos endpoints - HomeUiState: replace StringResource-based types with plain-string RepoItem, OrgItem, NotificationItem; add Error state - HomeViewModel: fetch repos/orgs/notifications in parallel via async/await - HomeScreen: render real data with RepoRow, OrgRow, NotificationRow; add error state with retry - ProfileUiState: rewrite as sealed class (Loading, Error, Success) - ProfileViewModel: fetch user, repos, orgs, starred in parallel - ProfileScreen: render real profile data; fix broken IconButton missing Icon call; add Loading/Error states with retry
There was a problem hiding this comment.
Code Review
This pull request significantly expands the GitHub client application by implementing a comprehensive navigation structure using Navigation Compose, integrating Ktor for API interactions, and adding several new screens including Home, Profile, Inbox, Explore, and Settings. It also establishes a 'No Hardcoding Policy' in the project documentation and provides platform-specific token storage implementations. The review feedback identifies a critical security issue regarding plain-text token storage on Android, incorrect ViewModel instantiation within composables, and violations of the new hardcoding policy. Additionally, there are suggestions to consolidate redundant dimension objects and ensure the UI state correctly reflects the PR's objectives regarding project counts.
| private val prefs: SharedPreferences = | ||
| context.getSharedPreferences("github_prefs", Context.MODE_PRIVATE) |
| } | ||
| composable<Route.Profile> { | ||
| ProfileScreen( | ||
| viewModel = ProfileViewModel(), |
There was a problem hiding this comment.
Directly instantiating ProfileViewModel() inside the composable block is incorrect. This causes a new ViewModel instance to be created on every recomposition or navigation entry, preventing it from being properly scoped to the navigation backstack or surviving configuration changes. Use the viewModel() factory method to correctly manage the ViewModel lifecycle.
| viewModel = ProfileViewModel(), | |
| viewModel = androidx.lifecycle.viewmodel.compose.viewModel { ProfileViewModel() }, |
| item { HomeDivider() } | ||
|
|
||
| // Organizations | ||
| item { SectionHeader(title = "Organizations") } |
There was a problem hiding this comment.
Hardcoded string "Organizations" violates the "No Hardcoding Policy" defined in AGENTS.md. All user-visible strings must be moved to strings.xml and accessed via stringResource().
| item { SectionHeader(title = "Organizations") } | |
| item { SectionHeader(title = stringResource(Res.string.nav_organizations)) } |
References
- All user-visible strings -> strings.xml + stringResource() (link)
|
|
||
| import androidx.compose.ui.unit.dp | ||
|
|
||
| object Dimensions { |
There was a problem hiding this comment.
| val publicRepos: Int, | ||
| val popularRepos: List<PopularRepo>, | ||
| val orgs: List<OrgSummary>, | ||
| val starredCount: Int |
| } | ||
| }, | ||
| label = stringResource(Res.string.nav_projects), | ||
| count = 0, |
No description provided.