refactor(settings): Relocate Settings feature to Profile#261
refactor(settings): Relocate Settings feature to Profile#261rainxchzed wants to merge 2 commits intomainfrom
Conversation
This commit refactors the `settings` feature module into a new `profile` module. This change better reflects the content and purpose of the screen, which includes user profile information, settings, and other related actions. All existing functionality from the `settings` module—including appearance settings, about section, and logout logic—has been migrated to the new `profile` module. Corresponding package names, class names, and Gradle module dependencies have been updated throughout the codebase to reflect this change. - **refactor(module)**: Renamed the `feature/settings` module to `feature/profile`. - **refactor(navigation)**: Updated `AppNavigation` and `GithubStoreGraph` to use `ProfileScreen` instead of `SettingsScreen`. - **refactor(di)**: Renamed `SettingsViewModel` to `ProfileViewModel` and updated the dependency injection configuration. - **chore(build)**: Updated `settings.gradle.kts` and `composeApp/build.gradle.kts` to reflect the module rename. - **chore(db)**: Added a new Room schema for version 3.
WalkthroughThis pull request migrates the application from a Settings feature module to a Profile feature module, updating all dependencies, navigation references, and presentation layer components. It introduces new domain models (UserProfile), repositories (ProfileRepository), and UI components (GitHubStoreImage, AccountSection, SectionText) while renaming existing classes and updating string resources across multiple locales. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
feature/profile/data/src/commonMain/kotlin/zed/rainxch/settings/data/repository/SettingsRepositoryImpl.kt (1)
1-10:⚠️ Potential issue | 🟡 MinorUpdate the package to the profile namespace.
The file now lives under
feature/profile, but the package is stillzed.rainxch.settings.data.repository, which violates the requiredzed.rainxch.{module}.{layer}pattern and leaves the refactor incomplete. Rename the package to the profile namespace and adjust imports accordingly.💡 Suggested change
-package zed.rainxch.settings.data.repository +package zed.rainxch.feature.profile.data.repositoryAs per coding guidelines:
**/*.kt: Organize packages followingzed.rainxch.{module}.{layer}pattern (e.g.,zed.rainxch.feature.home.presentation).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/data/src/commonMain/kotlin/zed/rainxch/settings/data/repository/SettingsRepositoryImpl.kt` around lines 1 - 10, The package declaration in SettingsRepositoryImpl.kt is still zed.rainxch.settings.data.repository but the file was moved under the profile feature; change the package to follow the required pattern (e.g., zed.rainxch.feature.profile.data.repository) and update any affected imports/usages (such as TokenStore, AuthenticationState, BuildKonfig, and SettingsRepository references) to the new package so the class compiles and follows zed.rainxch.{module}.{layer} conventions.feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/Account.kt (1)
1-35:⚠️ Potential issue | 🟠 MajorFix package namespace to match the Profile module.
This file lives underfeature/profile/...but still declareszed.rainxch.settings..., which breaks the package convention and keeps the Profile feature under the old namespace. Update the package declaration and adjust call sites (e.g., imports inProfileRoot.kt) accordingly.🔧 Suggested fix
- package zed.rainxch.settings.presentation.components.sections + package zed.rainxch.profile.presentation.components.sectionsAs per coding guidelines, organize packages following
zed.rainxch.{module}.{layer}pattern (e.g.,zed.rainxch.feature.home.presentation).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/Account.kt` around lines 1 - 35, The package declaration at the top of Account.kt is incorrect (currently using zed.rainxch.settings.presentation.components.sections) and must be changed to the Profile module namespace to match its file path (e.g., zed.rainxch.profile.presentation.components.sections); update the package line, then update all call sites and imports (for example in ProfileRoot.kt and any other files importing logout or symbols from Account.kt such as the logout LazyListScope extension) to the new package, rebuild and run tests to ensure no unresolved imports remain.feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/About.kt (1)
1-39:⚠️ Potential issue | 🟠 MajorFix package namespace to match the Profile module.
This file is underfeature/profile/...but still declareszed.rainxch.settings.... Please update the package to the Profile namespace and adjust imports where used.🔧 Suggested fix
- package zed.rainxch.settings.presentation.components.sections + package zed.rainxch.profile.presentation.components.sectionsAs per coding guidelines, organize packages following
zed.rainxch.{module}.{layer}pattern (e.g.,zed.rainxch.feature.home.presentation).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/About.kt` around lines 1 - 39, The package declaration is incorrect for the Profile feature; change the package at the top of About.kt from "zed.rainxch.settings.presentation.components.sections" to the Profile namespace (e.g., "zed.rainxch.profile.presentation.components.sections") so it matches the module location, and then update any imports/usages that reference the old package across the codebase (references to the LazyListScope.about function / About.kt) to the new package name so compilation and imports resolve correctly.
♻️ Duplicate comments (3)
feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileState.kt (1)
1-14: Package name should include thefeaturesegment (same as ProfileEvent.kt).As per coding guidelines: "Organize packages following
zed.rainxch.{module}.{layer}pattern".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileState.kt` around lines 1 - 14, The package declaration at the top of ProfileState.kt is missing the feature segment; update the package to match the project's package pattern and the sibling file (same as ProfileEvent.kt) so ProfileState uses zed.rainxch.feature.profile.presentation; locate the ProfileState data class and change only the package line to include "feature" so the file follows zed.rainxch.{module}.{layer} organization.feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileViewModel.kt (1)
1-1: Package name should include thefeaturesegment (same as ProfileEvent.kt).As per coding guidelines: "Organize packages following
zed.rainxch.{module}.{layer}pattern".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileViewModel.kt` at line 1, The package declaration in ProfileViewModel.kt is missing the required feature segment; update the package line to match the project's package pattern used by ProfileEvent.kt (zed.rainxch.feature.profile.presentation) so the file sits under zed.rainxch.feature.profile.presentation and aligns with the zed.rainxch.{module}.{layer} convention; update the package declaration at the top of ProfileViewModel.kt (and any imports/usages if necessary) to the correct package name.feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileAction.kt (1)
1-16: Same package/ sealed-class guideline as ProfileEvent.kt.As per coding guidelines: "Organize packages following
zed.rainxch.{module}.{layer}pattern" and "Use sealed classes for type-safe navigation routes, actions, and events".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileAction.kt` around lines 1 - 16, Update this file to match the same package and sealed-class style used by ProfileEvent.kt: change the package declaration to the identical package used by ProfileEvent, replace "sealed interface ProfileAction" with "sealed class ProfileAction", convert the singleton cases (currently declared as "data object" like OnNavigateBackClick, OnLogoutClick, OnLogoutConfirmClick, OnLogoutDismiss, OnHelpClick) to plain "object" singletons, and keep the parameterized entries as data classes (OnThemeColorSelected, OnAmoledThemeToggled, OnDarkThemeChange, OnFontThemeSelected); ensure the type names (ProfileAction, OnNavigateBackClick, OnThemeColorSelected, etc.) remain unchanged.
🧹 Nitpick comments (1)
feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileEvent.kt (1)
1-6: Align package path and sealed type with guidelines.Use
zed.rainxch.feature.profile.presentationand switch to a sealed class for events.♻️ Suggested update
-package zed.rainxch.profile.presentation +package zed.rainxch.feature.profile.presentation -sealed interface ProfileEvent { - data object OnLogoutSuccessful : ProfileEvent - data class OnLogoutError(val message: String) : ProfileEvent -} +sealed class ProfileEvent { + data object OnLogoutSuccessful : ProfileEvent() + data class OnLogoutError(val message: String) : ProfileEvent() +}As per coding guidelines: "Organize packages following
zed.rainxch.{module}.{layer}pattern" and "Use sealed classes for type-safe navigation routes, actions, and events".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileEvent.kt` around lines 1 - 6, Change the package declaration to "zed.rainxch.feature.profile.presentation" and convert the sealed interface ProfileEvent into a sealed class; update its members so the success variant is an object (OnLogoutSuccessful) and the error variant remains a data class (OnLogoutError) inheriting from ProfileEvent (use the class-style inheritance syntax), ensuring constructors and inheritance use the sealed class pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In
`@feature/profile/data/src/commonMain/kotlin/zed/rainxch/settings/data/repository/SettingsRepositoryImpl.kt`:
- Around line 1-10: The package declaration in SettingsRepositoryImpl.kt is
still zed.rainxch.settings.data.repository but the file was moved under the
profile feature; change the package to follow the required pattern (e.g.,
zed.rainxch.feature.profile.data.repository) and update any affected
imports/usages (such as TokenStore, AuthenticationState, BuildKonfig, and
SettingsRepository references) to the new package so the class compiles and
follows zed.rainxch.{module}.{layer} conventions.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/About.kt`:
- Around line 1-39: The package declaration is incorrect for the Profile
feature; change the package at the top of About.kt from
"zed.rainxch.settings.presentation.components.sections" to the Profile namespace
(e.g., "zed.rainxch.profile.presentation.components.sections") so it matches the
module location, and then update any imports/usages that reference the old
package across the codebase (references to the LazyListScope.about function /
About.kt) to the new package name so compilation and imports resolve correctly.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/Account.kt`:
- Around line 1-35: The package declaration at the top of Account.kt is
incorrect (currently using
zed.rainxch.settings.presentation.components.sections) and must be changed to
the Profile module namespace to match its file path (e.g.,
zed.rainxch.profile.presentation.components.sections); update the package line,
then update all call sites and imports (for example in ProfileRoot.kt and any
other files importing logout or symbols from Account.kt such as the logout
LazyListScope extension) to the new package, rebuild and run tests to ensure no
unresolved imports remain.
---
Duplicate comments:
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileAction.kt`:
- Around line 1-16: Update this file to match the same package and sealed-class
style used by ProfileEvent.kt: change the package declaration to the identical
package used by ProfileEvent, replace "sealed interface ProfileAction" with
"sealed class ProfileAction", convert the singleton cases (currently declared as
"data object" like OnNavigateBackClick, OnLogoutClick, OnLogoutConfirmClick,
OnLogoutDismiss, OnHelpClick) to plain "object" singletons, and keep the
parameterized entries as data classes (OnThemeColorSelected,
OnAmoledThemeToggled, OnDarkThemeChange, OnFontThemeSelected); ensure the type
names (ProfileAction, OnNavigateBackClick, OnThemeColorSelected, etc.) remain
unchanged.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileState.kt`:
- Around line 1-14: The package declaration at the top of ProfileState.kt is
missing the feature segment; update the package to match the project's package
pattern and the sibling file (same as ProfileEvent.kt) so ProfileState uses
zed.rainxch.feature.profile.presentation; locate the ProfileState data class and
change only the package line to include "feature" so the file follows
zed.rainxch.{module}.{layer} organization.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileViewModel.kt`:
- Line 1: The package declaration in ProfileViewModel.kt is missing the required
feature segment; update the package line to match the project's package pattern
used by ProfileEvent.kt (zed.rainxch.feature.profile.presentation) so the file
sits under zed.rainxch.feature.profile.presentation and aligns with the
zed.rainxch.{module}.{layer} convention; update the package declaration at the
top of ProfileViewModel.kt (and any imports/usages if necessary) to the correct
package name.
---
Nitpick comments:
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileEvent.kt`:
- Around line 1-6: Change the package declaration to
"zed.rainxch.feature.profile.presentation" and convert the sealed interface
ProfileEvent into a sealed class; update its members so the success variant is
an object (OnLogoutSuccessful) and the error variant remains a data class
(OnLogoutError) inheriting from ProfileEvent (use the class-style inheritance
syntax), ensuring constructors and inheritance use the sealed class pattern.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (31)
composeApp/build.gradle.ktscomposeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/di/ViewModelsModule.ktcomposeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/AppNavigation.ktcomposeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/BottomNavigationUtils.ktcomposeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/GithubStoreGraph.ktcomposeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/NavigationUtils.ktcore/data/schemas/zed.rainxch.core.data.local.db.AppDatabase/3.jsonfeature/profile/data/.gitignorefeature/profile/data/build.gradle.ktsfeature/profile/data/src/androidMain/AndroidManifest.xmlfeature/profile/data/src/commonMain/kotlin/zed/rainxch/settings/data/di/SharedModule.ktfeature/profile/data/src/commonMain/kotlin/zed/rainxch/settings/data/repository/SettingsRepositoryImpl.ktfeature/profile/domain/.gitignorefeature/profile/domain/build.gradle.ktsfeature/profile/domain/src/androidMain/AndroidManifest.xmlfeature/profile/domain/src/commonMain/kotlin/zed/rainxch/settings/domain/repository/SettingsRepository.ktfeature/profile/presentation/.gitignorefeature/profile/presentation/build.gradle.ktsfeature/profile/presentation/src/androidMain/AndroidManifest.xmlfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileAction.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileEvent.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileRoot.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileState.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileViewModel.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/LogoutDialog.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/About.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/Account.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/Appearance.ktfeature/settings/presentation/src/commonMain/kotlin/zed/rainxch/settings/presentation/SettingsAction.ktfeature/settings/presentation/src/commonMain/kotlin/zed/rainxch/settings/presentation/SettingsEvent.ktsettings.gradle.kts
💤 Files with no reviewable changes (2)
- feature/settings/presentation/src/commonMain/kotlin/zed/rainxch/settings/presentation/SettingsEvent.kt
- feature/settings/presentation/src/commonMain/kotlin/zed/rainxch/settings/presentation/SettingsAction.kt
…ile UI This commit refactors the "Settings" feature into "Profile", including renaming repositories, data models, and UI components. It also introduces a new user profile section in the UI and updates translations across multiple languages. - **refactor**: Renamed `SettingsRepository` to `ProfileRepository` and updated its implementation and DI modules. - **feat(profile)**: Added `UserProfile` domain model and `accountSection` to display user information (avatar, etc.) in `ProfileRoot`. - **feat(profile)**: Reorganized `ProfileRoot` into modular sections: `profile`, `settings`, `about`, and `logout`. - **feat(i18n)**: Renamed `settings_title` to `profile_title` and updated translations for `ru`, `tr`, `bn`, `zh-rCN`, `es`, `fr`, `it`, `hi`, `ja`, `kr`, and `pl`. - **refactor(presentation)**: Created `GitHubStoreImage` component to unify image loading logic using Coil and shared it across `RepositoryCard` and profile sections. - **ui**: Added `SectionHeader` and `SectionTitle` components for consistent layout in the profile screen.
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
feature/profile/data/src/commonMain/kotlin/zed/rainxch/profile/data/repository/ProfileRepositoryImpl.kt (1)
11-27:⚠️ Potential issue | 🔴 Critical
getUser()declared inProfileRepositorybut never implemented — compile error.
ProfileRepositorydeclaresfun getUser(): Flow<UserProfile?>(line 8 ofProfileRepository.kt) butProfileRepositoryImplprovides nooverride fun getUser()body. Kotlin will reject this with "Class 'ProfileRepositoryImpl' is not abstract and does not implement abstract member 'getUser'."A stub implementation is needed at minimum:
🐛 Proposed fix (stub — replace with real data-source call)
+ override fun getUser(): Flow<UserProfile?> { + // TODO: fetch from remote/local data source + return kotlinx.coroutines.flow.flowOf(null) + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/data/src/commonMain/kotlin/zed/rainxch/profile/data/repository/ProfileRepositoryImpl.kt` around lines 11 - 27, ProfileRepositoryImpl is missing the required override for fun getUser(): Flow<UserProfile?> declared in ProfileRepository, causing a compile error; add an override fun getUser(): Flow<UserProfile?> to ProfileRepositoryImpl that returns a Flow (at minimum a stub Flow emitting null) and ensure it is executed on the IO dispatcher (e.g., use flow { ... }.flowOn(Dispatchers.IO)) or map an existing authenticationState/TokenStore flow to UserProfile as appropriate; reference the class ProfileRepositoryImpl, the method getUser(), the interface ProfileRepository and the UserProfile type when making the change.feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/LogoutDialog.kt (1)
71-83:⚠️ Potential issue | 🟡 MinorLogout button text color overrides the button's
contentColor, risking contrast issues.The
ButtonsetscontentColor = MaterialTheme.colorScheme.onErrorContainer(appropriate for anerrorContainerbackground), but theTextinside explicitly setscolor = MaterialTheme.colorScheme.onSurface, discarding that. In themes whereonSurfacehas insufficient contrast againsterrorContainer, the label becomes hard to read.🎨 Proposed fix
Button( onClick = onLogout, colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.errorContainer, contentColor = MaterialTheme.colorScheme.onErrorContainer ) ) { Text( text = stringResource(Res.string.logout), style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurface ) }Removing the explicit
colorlets the button'scontentColorpropagate correctly throughLocalContentColor.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/LogoutDialog.kt` around lines 71 - 83, The Text inside the logout Button is overriding the Button's contentColor and breaking contrast; in LogoutDialog.kt remove the explicit color usage on the Text so it inherits the Button's contentColor (set via ButtonDefaults.buttonColors) instead—locate the Button(...) block where onClick = onLogout and the nested Text(...) and delete the color = MaterialTheme.colorScheme.onSurface property so LocalContentColor drives the label color.feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileViewModel.kt (1)
27-35:⚠️ Potential issue | 🟠 Major
userProfileis never populated —profileRepository.getUser()is not called anywhere.The
onStartblock only invokesloadCurrentTheme(),collectIsUserLoggedIn(), andloadVersionName(). There is no corresponding call to load the authenticated user's profile, soProfileState.userProfilewill always staynull. TheAccountSectionhas an explicitnullcheck for this field and is designed to display the user's avatar when populated — but that path is unreachable.Add a
loadUserProfile()function and call it from the initialization block:🐛 Proposed fix
if (!hasLoadedInitialData) { loadCurrentTheme() collectIsUserLoggedIn() loadVersionName() + loadUserProfile() hasLoadedInitialData = true }+private fun loadUserProfile() { + viewModelScope.launch { + profileRepository.getUser()?.let { user -> + _state.update { it.copy(userProfile = user) } + } + } +}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileViewModel.kt` around lines 27 - 35, The ProfileState.userProfile is never set because profileRepository.getUser() is not invoked; add a loadUserProfile() suspending function in ProfileViewModel that calls profileRepository.getUser() and updates the state (ProfileState.userProfile) accordingly, then call loadUserProfile() inside the existing onStart block alongside loadCurrentTheme(), collectIsUserLoggedIn(), and loadVersionName() (guarded by hasLoadedInitialData) so the AccountSection can see the populated userProfile.
♻️ Duplicate comments (1)
composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/di/initKoin.kt (1)
34-34:settingsModuleidentifier is stale — see theSharedModule.ktcomment.Once
SharedModule.ktrenames the variable toprofileModule, this reference must be updated to match.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/di/initKoin.kt` at line 34, Update the stale identifier reference: replace the use of settingsModule in the Koin initialization list with the new name profileModule to match the renaming in SharedModule.kt; locate the registration site (e.g., the initKoin or module list where settingsModule is referenced) and change that symbol to profileModule so the DI module resolves correctly.
🧹 Nitpick comments (6)
core/presentation/src/commonMain/composeResources/values-kr/strings-kr.xml (1)
105-105:profile_title,profile(line 178), andbottom_nav_profile_title(line 335) all share the same Korean value "프로필".While linguistically correct, the value collision across three distinct keys can silently mislead future translators who update one entry and expect the others to differ. Adding a brief distinguishing comment next to each key (e.g.,
<!-- Screen title -->,<!-- Author label -->,<!-- Bottom nav label -->) would make the intent clear.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core/presentation/src/commonMain/composeResources/values-kr/strings-kr.xml` at line 105, The three Korean string resources profile_title, profile, and bottom_nav_profile_title currently share the same value "프로필"; add short XML comments next to each <string> entry to clarify intent (for example: <!-- Screen title --> next to profile_title, <!-- Author label --> next to profile, and <!-- Bottom nav label --> next to bottom_nav_profile_title) so future translators know the distinct usage contexts; update the entries for profile_title, profile, and bottom_nav_profile_title accordingly.feature/profile/domain/src/commonMain/kotlin/zed/rainxch/profile/domain/repository/ProfileRepository.kt (1)
9-9:getVersionName()is a minor SRP concern — consider a dedicated abstraction.Retrieving the app build version is unrelated to user profile state. A thin
AppInfoRepositoryor a simple top-level function incore.domainwould be a cleaner home for this. Low priority since this predates the PR, but worth tracking.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/domain/src/commonMain/kotlin/zed/rainxch/profile/domain/repository/ProfileRepository.kt` at line 9, The ProfileRepository interface currently exposes getVersionName(), which breaks SRP; remove getVersionName() from ProfileRepository and introduce a dedicated abstraction (e.g., an AppInfoRepository interface with fun getVersionName(): String or a top-level function in core.domain) to own build/version retrieval; update all callers to depend on the new AppInfoRepository (or call the top-level function) and implement platform-specific providers where ProfileRepository was previously implemented, ensuring you delete getVersionName() from ProfileRepository and wire the new AppInfoRepository into DI or constructor parameters in places that need the version.feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/AccountSection.kt (2)
55-65:AccountSectionPreviewispublic— preview composables should beprivate.♻️ Proposed fix
`@Preview`(showBackground = true) `@Composable` -fun AccountSectionPreview() { +private fun AccountSectionPreview() {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/AccountSection.kt` around lines 55 - 65, The preview composable AccountSectionPreview is declared public but should be private; change its visibility to private (private fun AccountSectionPreview()) so the preview is not exposed as part of the public API, leaving the body (GithubStoreTheme, LazyColumn, accountSection call with ProfileState and onAction) unchanged.
25-27:onActionparameter is accepted but never used.The current implementation has no interactive elements in the account section, so
onActionis dead. Either remove it (and update callers) or add a//TODO: wire onAction when profile tap/edit is implementedcomment to signal intent.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/AccountSection.kt` around lines 25 - 27, The accountSection function currently accepts an unused onAction parameter (ProfileAction) which is dead code; either remove the onAction parameter from accountSection(state: ProfileState, onAction: (ProfileAction) -> Unit) and update all callers to stop passing a handler, or keep the parameter but add a clear TODO comment inside accountSection (e.g., "// TODO: wire onAction when profile tap/edit is implemented") so intent is recorded; if you choose removal, also update any usages to the new signature and adjust imports/types referencing ProfileAction accordingly.feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/SettingsSection.kt (1)
1-15:SettingsSection.kt/settings()naming is inconsistent with the module-rename goal.This PR's stated objective is to move away from the "Settings" naming entirely, yet the file is still named
SettingsSection.ktand the extension function is stillsettings(). This is jarring inside theprofilemodule.Consider either:
- Renaming the file to
PreferencesSection.kt(orAppearanceSection.kt) and the function topreferences()/appearanceSection()if this only ever wraps appearance, or- Keeping the
settings()name but renaming the file toProfileSettingsSection.ktto make it clear it is the settings sub-section of the profile screen.
ProfileRoot.ktcallssettings(state, onAction)at line 134, which should be updated to match.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/SettingsSection.kt` around lines 1 - 15, The file and function still use "Settings" although the module is being renamed away from that term; rename the extension function settings() and/or the file to match the new naming convention and update its callers: either rename the file SettingsSection.kt -> PreferencesSection.kt (or AppearanceSection.kt) and change the function name to preferences() (or appearanceSection()) if it only wraps appearanceSection(...), or keep the broader name and rename the file to ProfileSettingsSection.kt; then update the call in ProfileRoot.kt (where settings(state, onAction) is invoked) to the new function name so imports and references compile.feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileRoot.kt (1)
165-192: LocalTopAppBarfunction shadows the imported Material3TopAppBar— consider renaming.The private function
TopAppBar(onAction: (ProfileAction) -> Unit)has the same name as the importedandroidx.compose.material3.TopAppBar. It works because the signatures are distinct, but the shadowing creates readability confusion — especially whenTopAppBar(navigationIcon = ..., title = ...)inside the function body resolves to M3's API only by signature matching. A name likeProfileTopAppBarorTopBarremoves the ambiguity.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileRoot.kt` around lines 165 - 192, The private Composable function TopAppBar(onAction: (ProfileAction) -> Unit) shadows the imported androidx.compose.material3.TopAppBar and should be renamed (e.g., ProfileTopAppBar or TopBar) to remove ambiguity; change the function name declaration (TopAppBar) to the new name, keep the same parameters and annotations (`@OptIn`, `@Composable`), update all call sites that invoke TopAppBar(...) to use the new name, and verify the internal call to Material3's TopAppBar(navigationIcon = ..., title = ...) remains unchanged so it resolves to the library component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml`:
- Around line 106-107: The XML section comment is stale: replace the comment
text <!-- Settings --> with <!-- Profile --> so it accurately reflects the
section that contains the profile string (look for the string resource named
"profile_title") to avoid misleading future contributors; update the comment
directly above or near the <string name="profile_title"> entry.
In `@core/presentation/src/commonMain/composeResources/values-kr/strings-kr.xml`:
- Around line 104-105: Update the stale XML section comment so it accurately
describes the key: replace the comment string "<!-- Settings -->" with "<!--
Profile -->" near the localized string entry for profile_title to match the
renamed key (string name="profile_title") and avoid misleading section headers.
In
`@core/presentation/src/commonMain/kotlin/zed/rainxch/core/presentation/components/GitHubStoreImage.kt`:
- Around line 44-49: The Icon currently uses contentDescription = null which
hides the failure state from assistive tech; update the Icon in
GitHubStoreImage.kt to provide a meaningful, localized content description
(e.g., use stringResource(R.string.image_load_failed) or an appropriate platform
string accessor) instead of null so screen readers announce the image-load
failure; ensure the string resource key (e.g., image_load_failed) is added to
your i18n resources and referenced via stringResource(...) in the composable.
In
`@feature/profile/data/src/commonMain/kotlin/zed/rainxch/profile/data/di/SharedModule.kt`:
- Around line 7-14: Rename the stale module identifier settingsModule to
profileModule in SharedModule.kt and update its references where consumed (e.g.,
the consumer in initKoin.kt) so the Koin module name matches the feature; modify
the declaration val settingsModule = module { ... } to val profileModule =
module { ... } and replace any usages of settingsModule with profileModule
(notably the consumer call in initKoin.kt) to complete the settings→profile
rename.
In
`@feature/profile/domain/src/commonMain/kotlin/zed/rainxch/profile/domain/model/UserProfile.kt`:
- Around line 3-12: The UserProfile data class currently declares name and bio
as non-nullable Strings which will fail when GitHub returns null; update the
UserProfile class (data class UserProfile) to make the name and bio properties
nullable (String?), adjust any callers or deserialization expectations to handle
null values safely (e.g., defaulting or null checks), and run tests to ensure
serialization/deserialization and downstream code handle the nullable types.
- Line 4: The UserProfile data model declares val id: Int which can overflow for
GitHub 64-bit IDs; change the property type to Long in the UserProfile class
(update any related constructors, equals/hashCode/serializers, and usages that
construct or parse UserProfile) so id is stored and propagated as a Long to
avoid truncation.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/AccountSection.kt`:
- Around line 35-47: The current GitHubStoreImage call passes
Icons.Outlined.AccountCircle (an ImageVector) as imageModel which Coil cannot
load; update AccountSection so you branch on state.userProfile before invoking
GitHubStoreImage: if state.userProfile == null render a plain Compose
Icon(Icons.Outlined.AccountCircle, ...) with the same
Modifier/clip/size/background, otherwise call GitHubStoreImage with imageModel =
state.userProfile.imageUrl; ensure you remove passing ImageVector into
GitHubStoreImage and keep UI modifiers consistent between the two branches.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileViewModel.kt`:
- Around line 133-138: In ProfileViewModel's logout failure handler (the
onFailure after calling profileRepository.logout()), don't drop errors with null
messages: always emit a ProfileEvent.OnLogoutError via _events.send and close
the dialog via _state.update; if error.message is null/blank, send a fallback
message like "Logout failed" (or a localized equivalent) so the user gets
feedback; optionally also log the throwable for diagnostics.
---
Outside diff comments:
In
`@feature/profile/data/src/commonMain/kotlin/zed/rainxch/profile/data/repository/ProfileRepositoryImpl.kt`:
- Around line 11-27: ProfileRepositoryImpl is missing the required override for
fun getUser(): Flow<UserProfile?> declared in ProfileRepository, causing a
compile error; add an override fun getUser(): Flow<UserProfile?> to
ProfileRepositoryImpl that returns a Flow (at minimum a stub Flow emitting null)
and ensure it is executed on the IO dispatcher (e.g., use flow { ...
}.flowOn(Dispatchers.IO)) or map an existing authenticationState/TokenStore flow
to UserProfile as appropriate; reference the class ProfileRepositoryImpl, the
method getUser(), the interface ProfileRepository and the UserProfile type when
making the change.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/LogoutDialog.kt`:
- Around line 71-83: The Text inside the logout Button is overriding the
Button's contentColor and breaking contrast; in LogoutDialog.kt remove the
explicit color usage on the Text so it inherits the Button's contentColor (set
via ButtonDefaults.buttonColors) instead—locate the Button(...) block where
onClick = onLogout and the nested Text(...) and delete the color =
MaterialTheme.colorScheme.onSurface property so LocalContentColor drives the
label color.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileViewModel.kt`:
- Around line 27-35: The ProfileState.userProfile is never set because
profileRepository.getUser() is not invoked; add a loadUserProfile() suspending
function in ProfileViewModel that calls profileRepository.getUser() and updates
the state (ProfileState.userProfile) accordingly, then call loadUserProfile()
inside the existing onStart block alongside loadCurrentTheme(),
collectIsUserLoggedIn(), and loadVersionName() (guarded by hasLoadedInitialData)
so the AccountSection can see the populated userProfile.
---
Duplicate comments:
In `@composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/di/initKoin.kt`:
- Line 34: Update the stale identifier reference: replace the use of
settingsModule in the Koin initialization list with the new name profileModule
to match the renaming in SharedModule.kt; locate the registration site (e.g.,
the initKoin or module list where settingsModule is referenced) and change that
symbol to profileModule so the DI module resolves correctly.
---
Nitpick comments:
In `@core/presentation/src/commonMain/composeResources/values-kr/strings-kr.xml`:
- Line 105: The three Korean string resources profile_title, profile, and
bottom_nav_profile_title currently share the same value "프로필"; add short XML
comments next to each <string> entry to clarify intent (for example: <!-- Screen
title --> next to profile_title, <!-- Author label --> next to profile, and <!--
Bottom nav label --> next to bottom_nav_profile_title) so future translators
know the distinct usage contexts; update the entries for profile_title, profile,
and bottom_nav_profile_title accordingly.
In
`@feature/profile/domain/src/commonMain/kotlin/zed/rainxch/profile/domain/repository/ProfileRepository.kt`:
- Line 9: The ProfileRepository interface currently exposes getVersionName(),
which breaks SRP; remove getVersionName() from ProfileRepository and introduce a
dedicated abstraction (e.g., an AppInfoRepository interface with fun
getVersionName(): String or a top-level function in core.domain) to own
build/version retrieval; update all callers to depend on the new
AppInfoRepository (or call the top-level function) and implement
platform-specific providers where ProfileRepository was previously implemented,
ensuring you delete getVersionName() from ProfileRepository and wire the new
AppInfoRepository into DI or constructor parameters in places that need the
version.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/AccountSection.kt`:
- Around line 55-65: The preview composable AccountSectionPreview is declared
public but should be private; change its visibility to private (private fun
AccountSectionPreview()) so the preview is not exposed as part of the public
API, leaving the body (GithubStoreTheme, LazyColumn, accountSection call with
ProfileState and onAction) unchanged.
- Around line 25-27: The accountSection function currently accepts an unused
onAction parameter (ProfileAction) which is dead code; either remove the
onAction parameter from accountSection(state: ProfileState, onAction:
(ProfileAction) -> Unit) and update all callers to stop passing a handler, or
keep the parameter but add a clear TODO comment inside accountSection (e.g., "//
TODO: wire onAction when profile tap/edit is implemented") so intent is
recorded; if you choose removal, also update any usages to the new signature and
adjust imports/types referencing ProfileAction accordingly.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/SettingsSection.kt`:
- Around line 1-15: The file and function still use "Settings" although the
module is being renamed away from that term; rename the extension function
settings() and/or the file to match the new naming convention and update its
callers: either rename the file SettingsSection.kt -> PreferencesSection.kt (or
AppearanceSection.kt) and change the function name to preferences() (or
appearanceSection()) if it only wraps appearanceSection(...), or keep the
broader name and rename the file to ProfileSettingsSection.kt; then update the
call in ProfileRoot.kt (where settings(state, onAction) is invoked) to the new
function name so imports and references compile.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileRoot.kt`:
- Around line 165-192: The private Composable function TopAppBar(onAction:
(ProfileAction) -> Unit) shadows the imported
androidx.compose.material3.TopAppBar and should be renamed (e.g.,
ProfileTopAppBar or TopBar) to remove ambiguity; change the function name
declaration (TopAppBar) to the new name, keep the same parameters and
annotations (`@OptIn`, `@Composable`), update all call sites that invoke
TopAppBar(...) to use the new name, and verify the internal call to Material3's
TopAppBar(navigationIcon = ..., title = ...) remains unchanged so it resolves to
the library component.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (30)
composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/di/initKoin.ktcore/presentation/src/commonMain/composeResources/values-bn/strings-bn.xmlcore/presentation/src/commonMain/composeResources/values-es/strings-es.xmlcore/presentation/src/commonMain/composeResources/values-fr/strings-fr.xmlcore/presentation/src/commonMain/composeResources/values-hi/strings-hi.xmlcore/presentation/src/commonMain/composeResources/values-it/strings-it.xmlcore/presentation/src/commonMain/composeResources/values-ja/strings-ja.xmlcore/presentation/src/commonMain/composeResources/values-kr/strings-kr.xmlcore/presentation/src/commonMain/composeResources/values-pl/strings-pl.xmlcore/presentation/src/commonMain/composeResources/values-ru/strings-ru.xmlcore/presentation/src/commonMain/composeResources/values-tr/strings-tr.xmlcore/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xmlcore/presentation/src/commonMain/composeResources/values/strings.xmlcore/presentation/src/commonMain/kotlin/zed/rainxch/core/presentation/components/GitHubStoreImage.ktcore/presentation/src/commonMain/kotlin/zed/rainxch/core/presentation/components/RepositoryCard.ktfeature/profile/data/src/commonMain/kotlin/zed/rainxch/profile/data/di/SharedModule.ktfeature/profile/data/src/commonMain/kotlin/zed/rainxch/profile/data/repository/ProfileRepositoryImpl.ktfeature/profile/domain/src/commonMain/kotlin/zed/rainxch/profile/domain/model/UserProfile.ktfeature/profile/domain/src/commonMain/kotlin/zed/rainxch/profile/domain/repository/ProfileRepository.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileRoot.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileState.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileViewModel.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/LogoutDialog.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/SectionText.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/About.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/Account.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/AccountSection.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/Appearance.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/ProfileSection.ktfeature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/SettingsSection.kt
✅ Files skipped from review due to trivial changes (1)
- core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml
🚧 Files skipped from review as they are similar to previous changes (2)
- feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/Account.kt
- feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/About.kt
| <!-- Settings --> | ||
| <string name="settings_title">সেটিংস</string> | ||
| <string name="profile_title">প্রোফাইল</string> |
There was a problem hiding this comment.
Stale section comment — update <!-- Settings --> to <!-- Profile -->.
The XML comment on Line 106 still reads Settings, but the only key in this section is now profile_title. This will mislead future contributors looking for where to add profile-related strings.
✏️ Proposed fix
- <!-- Settings -->
+ <!-- Profile -->
<string name="profile_title">প্রোফাইল</string>📝 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.
| <!-- Settings --> | |
| <string name="settings_title">সেটিংস</string> | |
| <string name="profile_title">প্রোফাইল</string> | |
| <!-- Profile --> | |
| <string name="profile_title">প্রোফাইল</string> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml`
around lines 106 - 107, The XML section comment is stale: replace the comment
text <!-- Settings --> with <!-- Profile --> so it accurately reflects the
section that contains the profile string (look for the string resource named
"profile_title") to avoid misleading future contributors; update the comment
directly above or near the <string name="profile_title"> entry.
| <!-- Settings --> | ||
| <string name="settings_title">설정</string> | ||
| <string name="profile_title">프로필</string> |
There was a problem hiding this comment.
Stale section comment — update <!-- Settings --> to <!-- Profile -->.
The comment on line 104 still reads <!-- Settings --> but the key has been renamed to profile_title, making the comment misleading.
✏️ Proposed fix
- <!-- Settings -->
+ <!-- Profile -->
<string name="profile_title">프로필</string>📝 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.
| <!-- Settings --> | |
| <string name="settings_title">설정</string> | |
| <string name="profile_title">프로필</string> | |
| <!-- Profile --> | |
| <string name="profile_title">프로필</string> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@core/presentation/src/commonMain/composeResources/values-kr/strings-kr.xml`
around lines 104 - 105, Update the stale XML section comment so it accurately
describes the key: replace the comment string "<!-- Settings -->" with "<!--
Profile -->" near the localized string entry for profile_title to match the
renamed key (string name="profile_title") and avoid misleading section headers.
| Icon( | ||
| imageVector = Icons.Default.Warning, | ||
| contentDescription = null, | ||
| tint = MaterialTheme.colorScheme.error, | ||
| modifier = Modifier.fillMaxSize(.5f) | ||
| ) |
There was a problem hiding this comment.
Failure icon needs a meaningful contentDescription for accessibility.
contentDescription = null marks the icon as decorative and makes it invisible to screen readers. Since this icon is the sole indicator of an image-load failure, users relying on accessibility services receive no feedback about the error state.
♿ Proposed fix
- Icon(
- imageVector = Icons.Default.Warning,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.error,
- modifier = Modifier.fillMaxSize(.5f)
- )
+ Icon(
+ imageVector = Icons.Default.Warning,
+ contentDescription = "Image failed to load",
+ tint = MaterialTheme.colorScheme.error,
+ modifier = Modifier.fillMaxSize(.5f)
+ )Ideally, source this string from a string resource for proper localization.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@core/presentation/src/commonMain/kotlin/zed/rainxch/core/presentation/components/GitHubStoreImage.kt`
around lines 44 - 49, The Icon currently uses contentDescription = null which
hides the failure state from assistive tech; update the Icon in
GitHubStoreImage.kt to provide a meaningful, localized content description
(e.g., use stringResource(R.string.image_load_failed) or an appropriate platform
string accessor) instead of null so screen readers announce the image-load
failure; ensure the string resource key (e.g., image_load_failed) is added to
your i18n resources and referenced via stringResource(...) in the composable.
| val settingsModule = module { | ||
| single<ProfileRepository> { | ||
| ProfileRepositoryImpl( | ||
| authenticationState = get(), | ||
| tokenStore = get() | ||
| ) | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
settingsModule is a leftover name — should be profileModule.
The module is in zed.rainxch.profile.data.di and provides ProfileRepository, yet it's still named settingsModule. This is a core part of the PR's stated goal (rename settings → profile) that was missed. The same stale identifier is consumed in initKoin.kt at line 34.
♻️ Proposed fix
SharedModule.kt:
-val settingsModule = module {
+val profileModule = module {
single<ProfileRepository> {
ProfileRepositoryImpl(
authenticationState = get(),
tokenStore = get()
)
}
}initKoin.kt:
-import zed.rainxch.profile.data.di.settingsModule
+import zed.rainxch.profile.data.di.profileModule
...
- settingsModule
+ profileModule🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@feature/profile/data/src/commonMain/kotlin/zed/rainxch/profile/data/di/SharedModule.kt`
around lines 7 - 14, Rename the stale module identifier settingsModule to
profileModule in SharedModule.kt and update its references where consumed (e.g.,
the consumer in initKoin.kt) so the Koin module name matches the feature; modify
the declaration val settingsModule = module { ... } to val profileModule =
module { ... } and replace any usages of settingsModule with profileModule
(notably the consumer call in initKoin.kt) to complete the settings→profile
rename.
| data class UserProfile( | ||
| val id: Int, | ||
| val imageUrl: String, | ||
| val name: String, | ||
| val username: String, | ||
| val bio: String, | ||
| val repositoryCount: Int, | ||
| val followers: Int, | ||
| val following: Int, | ||
| ) |
There was a problem hiding this comment.
name and bio should be nullable to match the GitHub API contract.
The GitHub REST API returns null for both name (user's display name) and bio when not set. Non-nullable String fields here will cause a NullPointerException (or deserialization failure) for users who haven't filled in these fields.
🐛 Proposed fix
data class UserProfile(
val id: Int,
val imageUrl: String,
- val name: String,
+ val name: String?,
val username: String,
- val bio: String,
+ val bio: String?,
val repositoryCount: Int,
val followers: Int,
val following: Int,
)📝 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.
| data class UserProfile( | |
| val id: Int, | |
| val imageUrl: String, | |
| val name: String, | |
| val username: String, | |
| val bio: String, | |
| val repositoryCount: Int, | |
| val followers: Int, | |
| val following: Int, | |
| ) | |
| data class UserProfile( | |
| val id: Int, | |
| val imageUrl: String, | |
| val name: String?, | |
| val username: String, | |
| val bio: String?, | |
| val repositoryCount: Int, | |
| val followers: Int, | |
| val following: Int, | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@feature/profile/domain/src/commonMain/kotlin/zed/rainxch/profile/domain/model/UserProfile.kt`
around lines 3 - 12, The UserProfile data class currently declares name and bio
as non-nullable Strings which will fail when GitHub returns null; update the
UserProfile class (data class UserProfile) to make the name and bio properties
nullable (String?), adjust any callers or deserialization expectations to handle
null values safely (e.g., defaulting or null checks), and run tests to ensure
serialization/deserialization and downstream code handle the nullable types.
| package zed.rainxch.profile.domain.model | ||
|
|
||
| data class UserProfile( | ||
| val id: Int, |
There was a problem hiding this comment.
Prefer Long for id to avoid potential overflow.
GitHub user IDs are effectively unbounded integers. The GitHub REST API spec documents id as a 64-bit integer. Using Int (max ≈ 2.1 B) risks silent truncation for high-numbered IDs. GitHub's own Kotlin/JVM clients (e.g., the official Octokit) use Long for all entity IDs.
🛡️ Proposed fix
data class UserProfile(
- val id: Int,
+ val id: Long,
...
)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@feature/profile/domain/src/commonMain/kotlin/zed/rainxch/profile/domain/model/UserProfile.kt`
at line 4, The UserProfile data model declares val id: Int which can overflow
for GitHub 64-bit IDs; change the property type to Long in the UserProfile class
(update any related constructors, equals/hashCode/serializers, and usages that
construct or parse UserProfile) so id is stored and propagated as a Long to
avoid truncation.
| GitHubStoreImage( | ||
| imageModel = { | ||
| if (state.userProfile == null) { | ||
| Icons.Outlined.AccountCircle | ||
| } else { | ||
| state.userProfile.imageUrl | ||
| } | ||
| }, | ||
| modifier = Modifier | ||
| .size(100.dp) | ||
| .clip(CircleShape) | ||
| .background(MaterialTheme.colorScheme.surfaceContainerHigh) | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find the AccountSection.kt file
fd -t f "AccountSection.kt"Repository: rainxchzed/Github-Store
Length of output: 188
🏁 Script executed:
# Find GitHubStoreImage implementation
fd -t f ".*Image.*\.kt" | head -20Repository: rainxchzed/Github-Store
Length of output: 285
🏁 Script executed:
# Search for GitHubStoreImage definition
rg -t kt "GitHubStoreImage" --max-count=20Repository: rainxchzed/Github-Store
Length of output: 93
🏁 Script executed:
cat -n "feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/AccountSection.kt"Repository: rainxchzed/Github-Store
Length of output: 2708
🏁 Script executed:
cat -n "core/presentation/src/commonMain/kotlin/zed/rainxch/core/presentation/components/GitHubStoreImage.kt"Repository: rainxchzed/Github-Store
Length of output: 2379
🏁 Script executed:
# Find build files to check Coil3 version
fd -t f "build\.gradle.*|gradle\.kts|gradle\.properties" | head -10Repository: rainxchzed/Github-Store
Length of output: 376
🏁 Script executed:
# Search for other GitHubStoreImage usages to understand the pattern
rg "GitHubStoreImage" -A 5 -B 2Repository: rainxchzed/Github-Store
Length of output: 4910
🏁 Script executed:
# Check if there's any special handling or importing of imageModel types
rg "imageModel" -A 3 -B 3Repository: rainxchzed/Github-Store
Length of output: 10138
🏁 Script executed:
# Check composeApp build file for Coil3 version
cat "composeApp/build.gradle.kts"Repository: rainxchzed/Github-Store
Length of output: 6096
🏁 Script executed:
# Look for any gradle properties or version catalogs
cat "build-logic/gradle.properties" 2>/dev/null || echo "File not found"Repository: rainxchzed/Github-Store
Length of output: 149
🏁 Script executed:
# Find the version catalog
fd -t f "libs\.versions\.toml|version.*\.toml"Repository: rainxchzed/Github-Store
Length of output: 92
🏁 Script executed:
# Also check in gradle directory
find . -name "*.toml" -o -name "libs.gradle.kts"Repository: rainxchzed/Github-Store
Length of output: 94
🏁 Script executed:
cat "gradle/libs.versions.toml"Repository: rainxchzed/Github-Store
Length of output: 12491
ImageVector is not a Coil-supported imageModel type — the fallback avatar will render the failure state instead of AccountCircle.
Coil3 is designed to load images from URLs, files, or resource identifiers, not Compose drawing primitives like ImageVector. When state.userProfile == null, passing Icons.Outlined.AccountCircle to CoilImage will fail, and GitHubStoreImage's failure composable (a Warning icon) will render instead of the intended account circle placeholder.
Fix by branching on userProfile before reaching GitHubStoreImage, using a plain Icon for the null case:
🐛 Proposed fix
-GitHubStoreImage(
- imageModel = {
- if (state.userProfile == null) {
- Icons.Outlined.AccountCircle
- } else {
- state.userProfile.imageUrl
- }
- },
- modifier = Modifier
- .size(100.dp)
- .clip(CircleShape)
- .background(MaterialTheme.colorScheme.surfaceContainerHigh)
-)
+if (state.userProfile != null) {
+ GitHubStoreImage(
+ imageModel = { state.userProfile.imageUrl },
+ modifier = Modifier
+ .size(100.dp)
+ .clip(CircleShape)
+ .background(MaterialTheme.colorScheme.surfaceContainerHigh)
+ )
+} else {
+ Icon(
+ imageVector = Icons.Outlined.AccountCircle,
+ contentDescription = null,
+ modifier = Modifier
+ .size(100.dp)
+ .clip(CircleShape)
+ .background(MaterialTheme.colorScheme.surfaceContainerHigh),
+ tint = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/components/sections/AccountSection.kt`
around lines 35 - 47, The current GitHubStoreImage call passes
Icons.Outlined.AccountCircle (an ImageVector) as imageModel which Coil cannot
load; update AccountSection so you branch on state.userProfile before invoking
GitHubStoreImage: if state.userProfile == null render a plain Compose
Icon(Icons.Outlined.AccountCircle, ...) with the same
Modifier/clip/size/background, otherwise call GitHubStoreImage with imageModel =
state.userProfile.imageUrl; ensure you remove passing ImageVector into
GitHubStoreImage and keep UI modifiers consistent between the two branches.
| }.onFailure { error -> | ||
| _state.update { it.copy(isLogoutDialogVisible = false) } | ||
| error.message?.let { | ||
| _events.send(SettingsEvent.OnLogoutError(it)) | ||
| _events.send(ProfileEvent.OnLogoutError(it)) | ||
| } | ||
| } |
There was a problem hiding this comment.
Logout error is silently swallowed when error.message is null.
If profileRepository.logout() throws an exception with a null message, the onFailure block closes the dialog but emits no event, leaving the user with no feedback.
🐛 Proposed fix
.onFailure { error ->
_state.update { it.copy(isLogoutDialogVisible = false) }
- error.message?.let {
- _events.send(ProfileEvent.OnLogoutError(it))
- }
+ _events.send(ProfileEvent.OnLogoutError(error.message ?: "Unknown error"))
}📝 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.
| }.onFailure { error -> | |
| _state.update { it.copy(isLogoutDialogVisible = false) } | |
| error.message?.let { | |
| _events.send(SettingsEvent.OnLogoutError(it)) | |
| _events.send(ProfileEvent.OnLogoutError(it)) | |
| } | |
| } | |
| }.onFailure { error -> | |
| _state.update { it.copy(isLogoutDialogVisible = false) } | |
| _events.send(ProfileEvent.OnLogoutError(error.message ?: "Unknown error")) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileViewModel.kt`
around lines 133 - 138, In ProfileViewModel's logout failure handler (the
onFailure after calling profileRepository.logout()), don't drop errors with null
messages: always emit a ProfileEvent.OnLogoutError via _events.send and close
the dialog via _state.update; if error.message is null/blank, send a fallback
message like "Logout failed" (or a localized equivalent) so the user gets
feedback; optionally also log the throwable for diagnostics.
This commit refactors the
settingsfeature module into a newprofilemodule. This change better reflects the content and purpose of the screen, which includes user profile information, settings, and other related actions.All existing functionality from the
settingsmodule—including appearance settings, about section, and logout logic—has been migrated to the newprofilemodule. Corresponding package names, class names, and Gradle module dependencies have been updated throughout the codebase to reflect this change.feature/settingsmodule tofeature/profile.AppNavigationandGithubStoreGraphto useProfileScreeninstead ofSettingsScreen.SettingsViewModeltoProfileViewModeland updated the dependency injection configuration.settings.gradle.ktsandcomposeApp/build.gradle.ktsto reflect the module rename.Summary by CodeRabbit
New Features
UI/UX Improvements
Other