SCRUM-282 design: add blocked user management screen - #64
Conversation
Move the local action button component to the shared core design system directory as FeelinActionButton. Replace its usage in UserInfoScreen
Integrate BlockedUsersScreen into the mypage navigation graph. Add the destination to FeelinDestination, connect it in FeelinNavHost with mock data, and expose a menu item in SettingScreen.
Create BlockedUsersUiState and BlockedUsersViewModel to manage state. Update FeelinNavHost to inject the ViewModel within the MyPageGraph scope and collect its state, migrating away from the hardcoded list.
๐ WalkthroughWalkthroughThis PR adds a "Blocked Users" management feature: a new screen, ViewModel, UI state, and list item component, backed by new design-system components (FeelinActionButton, FeelinSnackbar/FeelinSnackbarHost). Navigation wiring connects Settings to the new screen, and existing screens are refactored to reuse the new action button. ChangesBlocked Users Feature
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant SettingScreen
participant FeelinNavHost
participant BlockedUsersViewModel
participant BlockedUsersScreen
SettingScreen->>FeelinNavHost: onBlockedUsersClick()
FeelinNavHost->>FeelinNavHost: navigate(BlockedUsers.route)
FeelinNavHost->>BlockedUsersViewModel: collect uiState
FeelinNavHost->>BlockedUsersScreen: render(blockedUsers)
BlockedUsersScreen->>BlockedUsersViewModel: onUnblockClick(userId)
BlockedUsersViewModel->>BlockedUsersViewModel: filter blockedUsers, update state
BlockedUsersScreen->>BlockedUsersScreen: show snackbar("์ฐจ๋จ ํด์ ๋์์ต๋๋ค")
Possibly related PRs
Suggested reviewers: ๐ฅ Pre-merge checks | โ 5โ Passed checks (5 passed)
โจ 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.
๐ก Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d3cce7ccb1
โน๏ธ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with ๐.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 3
๐งน Nitpick comments (7)
app/src/main/java/com/lyrics/feelin/core/designsystem/component/FeelinSnackbar.kt (2)
81-86: ๐ Maintainability & Code Quality | ๐ต Trivial | ๐ค Low valueIcon is hardcoded to a success checkmark for all snackbars.
Icons.Filled.CheckCircleis baked into the shared component regardless of message semantics. Since this snackbar is a general-purpose design-system component (already used for the unblock-success message), a future error/warning snackbar reusing this component would show a misleading success icon. Consider parameterizing the icon or adding atype/variantparam.๐ค Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/lyrics/feelin/core/designsystem/component/FeelinSnackbar.kt` around lines 81 - 86, The snackbar icon is hardcoded to Icons.Filled.CheckCircle in the shared FeelinSnackbar component, so all snackbar variants show a success symbol. Update FeelinSnackbar to accept an icon-related parameter or a type/variant value, and use that instead of the fixed checkmark so callers can supply the appropriate icon for success, warning, or error states.
63-94: ๐ฏ Functional Correctness | ๐ต Trivial | โก Quick winFixed-height Surface will clip longer messages.
The
Surfaceis a fixedheight(56.dp)and clipped toRoundedCornerShape(8.dp). Since the messageTexthas nomaxLines/overflowhandling, any message that wraps to more than one line will be clipped by the shape rather than the container growing to fit it.โป๏ธ Suggested fix
Surface( modifier = modifier .fillMaxWidth() - .height(56.dp) + .heightIn(min = 56.dp) .shadow(Text( text = message, style = FeelinTypography.body2, - color = textColor + color = textColor, + maxLines = 2, + overflow = TextOverflow.Ellipsis )๐ค Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/lyrics/feelin/core/designsystem/component/FeelinSnackbar.kt` around lines 63 - 94, The Snackbar layout in FeelinSnackbar is forcing a fixed height, which can clip multi-line messages. Update the Surface/Row sizing so the container can expand with content instead of using a hardcoded 56.dp height, and add appropriate text handling in the Text composable (for example line limits or overflow behavior) so longer messages are displayed cleanly without being cut off.app/src/main/java/com/lyrics/feelin/core/designsystem/component/FeelinActionButton.kt (2)
24-46: ๐ฏ Functional Correctness | ๐ต Trivial | โก Quick winText can clip inside the fixed-size box; no accessibility role.
The button's
Boxhas a hardcoded68.dp x 28.dpsize with nomaxLines/overflowhandling on the innerTextโ longer localized strings than "๋ณต์ฌ"/"์ฐจ๋จ ํด์ " will get clipped by the rounded-corner clip. Also,clickable(onClick = onClick)doesn't setrole = Role.Button, so screen readers won't announce this as an actionable button.โป๏ธ Suggested improvements
Text( text = text, style = FeelinTypography.body2.copy(color = feelinColors.brandPrimary), + maxLines = 1, + overflow = TextOverflow.Ellipsis, ).background(color = feelinColors.brandSecondary) - .clickable(onClick = onClick) + .clickable(role = Role.Button, onClick = onClick)๐ค Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/lyrics/feelin/core/designsystem/component/FeelinActionButton.kt` around lines 24 - 46, The FeelinActionButton composable is using a fixed-size Box that can clip longer localized labels and its clickable modifier is missing a button accessibility role. Update FeelinActionButton so the inner Text can safely fit or truncate by handling text overflow/max lines instead of relying on the hardcoded size, and keep the layout flexible enough for translations. Also change the Box click handling to use an explicit Role.Button in clickable so screen readers announce it as a button.
24-28: ๐ Maintainability & Code Quality | ๐ต Trivial | ๐ค Low valueParameter order deviates from lambda-last convention.
onClick(a lambda) is placed beforemodifier. Reordering to(text, modifier, onClick)follows the trailing-lambda convention used elsewhere and matches the project's stated composable parameter ordering preference for lambdas.๐ค Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/lyrics/feelin/core/designsystem/component/FeelinActionButton.kt` around lines 24 - 28, Reorder the FeelinActionButton composable parameters to follow the lambda-last convention by moving onClick after modifier, matching the project's composable ordering style used elsewhere. Update the FeelinActionButton function signature so it reads text, modifier, then onClick, and keep all call sites aligned with the new parameter order.app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersUiState.kt (1)
6-8: ๐ Maintainability & Code Quality | ๐ต Trivial | ๐ค Low valueRemove the unused
initial()factory.
BlockedUsersViewModelconstructsBlockedUsersUiStatedirectly, and there are no call sites forBlockedUsersUiState.initial(). Drop the factory or make the ViewModel use it as the base state.๐ค Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersUiState.kt` around lines 6 - 8, The BlockedUsersUiState companion object exposes an unused initial() factory that is not referenced anywhere, while BlockedUsersViewModel already creates BlockedUsersUiState directly. Remove the initial() method from BlockedUsersUiState, or alternatively update BlockedUsersViewModel to use BlockedUsersUiState.initial() consistently as its base state so there is a single construction path.app/src/main/java/com/lyrics/feelin/navigation/FeelinNavHost.kt (1)
350-350: ๐ Maintainability & Code Quality | ๐ต Trivial | โ๏ธ Poor tradeoff
@Suppress("LongMethod")masks growing complexity inmyPageNavGraph.Each new destination adds to the same function; consider extracting each
composable(...)block (e.g.,settingComposable,blockedUsersComposable) into private extension functions instead of suppressing the lint rule.๐ค Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/lyrics/feelin/navigation/FeelinNavHost.kt` at line 350, The `@Suppress("LongMethod")` on `myPageNavGraph` is hiding increasing complexity in the navigation setup. Remove the suppression and refactor the large `myPageNavGraph` function by extracting individual `composable(...)` blocks into private helper/extension functions such as `settingComposable` and `blockedUsersComposable`, then keep `myPageNavGraph` focused on wiring the graph together.app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/component/BlockedUserListItem.kt (1)
51-59: ๐ Maintainability & Code Quality | ๐ต Trivial | โก Quick winLocalize
contentDescriptionand add a placeholder forAsyncImage.
"Profile Image"is a hardcoded English string while the rest of the screen is Korean, and there's no placeholder/error drawable whenprofileImageUrlisnullor fails to load.๐ค Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/component/BlockedUserListItem.kt` around lines 51 - 59, Update BlockedUserListItemโs AsyncImage so the contentDescription is pulled from localized resources instead of the hardcoded English string, and add placeholder/error drawables for the image loading state. Use the AsyncImage call in BlockedUserListItem and the surrounding image modifier setup to wire in a fallback when data.profileImageUrl is null or fails to load, while keeping the existing size/clip/background styling.
๐ค Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersScreen.kt`:
- Around line 38-42: The BlockedUsersScreen composable has the lambda parameter
ordered before modifier, which conflicts with the composable parameter ordering
guidelines. Update the BlockedUsersScreen signature so modifier is the first
optional parameter after required data parameters, and move onBackClick to the
end of the parameter list to keep the lambda last.
In
`@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersViewModel.kt`:
- Around line 10-22: The BlockedUsersViewModel currently exposes only a
read-only uiState, so blockedUsers never changes after an unblock action. Add a
state-update method on BlockedUsersViewModel that removes the matching
BlockedUserListItemData from the current BlockedUsersUiState, then update
BlockedUsersScreen and FeelinNavHost to invoke that method from onUnblockClick
so the UI reflects the removal immediately.
In
`@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/component/BlockedUserListItem.kt`:
- Around line 32-36: The Composable signature for BlockedUserListItem should
follow the standard parameter order by moving modifier before the lambda so the
optional modifier comes first and onUnblockClick is last. Update the
BlockedUserListItem declaration accordingly, and keep the same ordering pattern
anywhere this composable is called to match the intended Compose API style.
---
Nitpick comments:
In
`@app/src/main/java/com/lyrics/feelin/core/designsystem/component/FeelinActionButton.kt`:
- Around line 24-46: The FeelinActionButton composable is using a fixed-size Box
that can clip longer localized labels and its clickable modifier is missing a
button accessibility role. Update FeelinActionButton so the inner Text can
safely fit or truncate by handling text overflow/max lines instead of relying on
the hardcoded size, and keep the layout flexible enough for translations. Also
change the Box click handling to use an explicit Role.Button in clickable so
screen readers announce it as a button.
- Around line 24-28: Reorder the FeelinActionButton composable parameters to
follow the lambda-last convention by moving onClick after modifier, matching the
project's composable ordering style used elsewhere. Update the
FeelinActionButton function signature so it reads text, modifier, then onClick,
and keep all call sites aligned with the new parameter order.
In
`@app/src/main/java/com/lyrics/feelin/core/designsystem/component/FeelinSnackbar.kt`:
- Around line 81-86: The snackbar icon is hardcoded to Icons.Filled.CheckCircle
in the shared FeelinSnackbar component, so all snackbar variants show a success
symbol. Update FeelinSnackbar to accept an icon-related parameter or a
type/variant value, and use that instead of the fixed checkmark so callers can
supply the appropriate icon for success, warning, or error states.
- Around line 63-94: The Snackbar layout in FeelinSnackbar is forcing a fixed
height, which can clip multi-line messages. Update the Surface/Row sizing so the
container can expand with content instead of using a hardcoded 56.dp height, and
add appropriate text handling in the Text composable (for example line limits or
overflow behavior) so longer messages are displayed cleanly without being cut
off.
In `@app/src/main/java/com/lyrics/feelin/navigation/FeelinNavHost.kt`:
- Line 350: The `@Suppress("LongMethod")` on `myPageNavGraph` is hiding
increasing complexity in the navigation setup. Remove the suppression and
refactor the large `myPageNavGraph` function by extracting individual
`composable(...)` blocks into private helper/extension functions such as
`settingComposable` and `blockedUsersComposable`, then keep `myPageNavGraph`
focused on wiring the graph together.
In
`@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersUiState.kt`:
- Around line 6-8: The BlockedUsersUiState companion object exposes an unused
initial() factory that is not referenced anywhere, while BlockedUsersViewModel
already creates BlockedUsersUiState directly. Remove the initial() method from
BlockedUsersUiState, or alternatively update BlockedUsersViewModel to use
BlockedUsersUiState.initial() consistently as its base state so there is a
single construction path.
In
`@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/component/BlockedUserListItem.kt`:
- Around line 51-59: Update BlockedUserListItemโs AsyncImage so the
contentDescription is pulled from localized resources instead of the hardcoded
English string, and add placeholder/error drawables for the image loading state.
Use the AsyncImage call in BlockedUserListItem and the surrounding image
modifier setup to wire in a fallback when data.profileImageUrl is null or fails
to load, while keeping the existing size/clip/background styling.
๐ช Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
โน๏ธ Review info
โ๏ธ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 3dbc3c41-f30e-4a9e-8ce6-8aa1a6b365c5
๐ Files selected for processing (13)
app/src/androidTest/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersScreenTest.ktapp/src/main/java/com/lyrics/feelin/core/designsystem/component/FeelinActionButton.ktapp/src/main/java/com/lyrics/feelin/core/designsystem/component/FeelinSnackbar.ktapp/src/main/java/com/lyrics/feelin/navigation/FeelinDestination.ktapp/src/main/java/com/lyrics/feelin/navigation/FeelinNavHost.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUserListItemData.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersScreen.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersUiState.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersViewModel.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/component/BlockedUserListItem.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/component/SettingInfoItem.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/setting/SettingScreen.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/userinfo/UserInfoScreen.kt
๐ค Files with no reviewable changes (1)
- app/src/main/java/com/lyrics/feelin/presentation/view/mypage/component/SettingInfoItem.kt
Add unblock functionality by introducing the unblockUser method to BlockedUsersViewModel and wiring it to BlockedUsersScreen. Additionally, move FeelinActionButton to the mypage component package to refine code structure.
|
@codex re-review this. |
There was a problem hiding this comment.
Actionable comments posted: 1
๐งน Nitpick comments (2)
app/src/main/java/com/lyrics/feelin/presentation/view/mypage/component/FeelinActionButton.kt (1)
1-1: ๐ Maintainability & Code Quality | ๐ต Trivial | ๐ค Low valueMove
onClickto the end of the parameter listFeelinActionButtonshould keep the lambda last, so the signature should betext,modifier,onClickto match the Compose guidelines.๐ค Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/component/FeelinActionButton.kt` at line 1, Update FeelinActionButton so its parameter order follows Compose conventions by moving the onClick lambda to the end of the signature after text and modifier. Locate the FeelinActionButton declaration in the mypage component and adjust any call sites if needed so the function keeps the trailing lambda style and matches the expected parameter ordering.Source: Coding guidelines
app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersScreen.kt (1)
91-96: ๐ฉบ Stability & Availability | ๐ต Trivial | โก Quick winSnackbar shows unconditionally regardless of unblock outcome.
onUnblockClick(user.userId)is called, then the success snackbar is launched without checking whether the operation actually succeeded. With current mock data this is harmless, but once backend integration lands, a failure would still show a success message. Consider gating the snackbar on the result of the unblock action.๐ค Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersScreen.kt` around lines 91 - 96, The unblock handler in BlockedUsersScreen currently launches the success snackbar immediately after onUnblockClick(user.userId), so it will show even if the unblock fails. Update the onUnblockClick callback flow to return or observe a success/failure result from the unblock action, and only call snackbarHostState.showSnackbar inside the success path. Use the existing onUnblockClick and coroutineScope launch block as the place to gate the snackbar on the actual outcome.
๐ค Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersScreen.kt`:
- Around line 92-95: The snackbar message in BlockedUsersScreenโs unblock flow
does not match the design spec; update the text used in the
coroutineScope.launch call that shows the snackbar after
onUnblockClick(user.userId) so it uses the honorific phrasing specified in the
PR (โ์ฐจ๋จ ํด์ ๋์
จ์ต๋๋คโ) instead of the current plain-form message.
---
Nitpick comments:
In
`@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersScreen.kt`:
- Around line 91-96: The unblock handler in BlockedUsersScreen currently
launches the success snackbar immediately after onUnblockClick(user.userId), so
it will show even if the unblock fails. Update the onUnblockClick callback flow
to return or observe a success/failure result from the unblock action, and only
call snackbarHostState.showSnackbar inside the success path. Use the existing
onUnblockClick and coroutineScope launch block as the place to gate the snackbar
on the actual outcome.
In
`@app/src/main/java/com/lyrics/feelin/presentation/view/mypage/component/FeelinActionButton.kt`:
- Line 1: Update FeelinActionButton so its parameter order follows Compose
conventions by moving the onClick lambda to the end of the signature after text
and modifier. Locate the FeelinActionButton declaration in the mypage component
and adjust any call sites if needed so the function keeps the trailing lambda
style and matches the expected parameter ordering.
๐ช Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
โน๏ธ Review info
โ๏ธ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 3c7d1ff9-3fff-4b2e-b571-31481a068d36
๐ Files selected for processing (6)
app/src/main/java/com/lyrics/feelin/navigation/FeelinNavHost.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersScreen.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersViewModel.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/component/BlockedUserListItem.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/component/FeelinActionButton.ktapp/src/main/java/com/lyrics/feelin/presentation/view/mypage/userinfo/UserInfoScreen.kt
๐ง Files skipped from review as they are similar to previous changes (4)
- app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/BlockedUsersViewModel.kt
- app/src/main/java/com/lyrics/feelin/presentation/view/mypage/blockedusers/component/BlockedUserListItem.kt
- app/src/main/java/com/lyrics/feelin/presentation/view/mypage/userinfo/UserInfoScreen.kt
- app/src/main/java/com/lyrics/feelin/navigation/FeelinNavHost.kt
There was a problem hiding this comment.
๐ก Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1f5b2cf730
โน๏ธ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with ๐.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
๋ณํฉํ๊ฒ ์ต๋๋ค. |
Please check if the PR fulfills these requirements
What kind of change does this PR introduce?
What is the current behavior?
๋ง์ดํ์ด์ง ์ค์ ๋ฉ๋ด ๋ด์ ์ฐจ๋จ๋ ์ ์ ๋ฅผ ๊ด๋ฆฌํ ์ ์๋ ํ๋ฉด์ผ๋ก์ ์ง์ ์ ์ด ์์ผ๋ฉฐ, ๊ด๋ จ ๊ธฐ๋ฅ์ ์ํ ํ๋ฉด UI๊ฐ ๊ตฌํ๋์ด ์์ง ์์ ์ํ์ ๋๋ค.
What is the new behavior (if this is a feature change)?
์ฐจ๋จ๋ ์ ์ ๋ชฉ๋ก์ ํ์ธํ๊ณ ๊ด๋ฆฌํ ์ ์๋ ํ๋ฉด์ ์ ๊ท ๊ตฌํํ์ต๋๋ค.
FeelinActionButton๊ณผFeelinSnackbar๋ฅผ ์ ๊ท ๊ตฌํํ๊ฑฐ๋ ์ถ์ถํ์ฌ ์ ์ฉํ์ต๋๋ค.Does this PR introduce a breaking change? (What changes might users need to make in their application due to this PR?)
์์.
ScreenShots (If needed)
Light mode
Dark mode
Other information:
AI Agent
./gradlew detekt๋ฐ./gradlew :app:assembleDebug๋ช ๋ น์ ํตํด ์ฝ๋ ํ์ง ๋ฐ ๋น๋ ์ ์ ์ฌ๋ถ๋ฅผ ํ์ธํ์ต๋๋ค.BlockedUsersScreen.kt: ์ฐจ๋จ ๋ชฉ๋ก UI ๋ฐ ํ๋ฉด ์ํ ๋ถ๊ธฐ ์ฒ๋ฆฌ.BlockedUsersViewModel.kt: UI ์ํ ๋ฐ ๋ชฉ์ ๋ฐ์ดํฐ ๊ด๋ฆฌ.FeelinActionButton.kt: ์ฌ๋ฌ ํ๋ฉด์์ ๊ณตํต์ผ๋ก ์ฌ์ฉํ ์ ์๋๋ก ์ถ์ถํ ๋ฒํผ ์ปดํฌ๋ํธ.FeelinSnackbar.kt: ์ปค์คํ ๋์์ธ์ด ์ ์ฉ๋ ์ ๊ท ๊ณตํต ์ค๋ต๋ฐ.FeelinNavHost.kt,FeelinDestination.kt: ๋จ๋น๊ฒ์ด์ ๊ฒฝ๋ก ์ ์ ๋ฐ ๋ง์ดํ์ด์ง ๊ทธ๋ํ ์ฐ๊ฒฐ.BlockedUsersScreenTest.kt: ๋ฆฌ์คํธ ์์ดํ ๋ฐ ์ค๋ต๋ฐ ๋ ธ์ถ ์ฌ๋ถ์ ๋ํ UI ํ ์คํธ ์ถ๊ฐ.User
์ด๋ฒ์ ์ถ๊ฐํ ์ค๋ต๋ฐ๊ฐ ์์คํ ๋ด๋น๋ฐ๊ฐ 3๋ฒํผ์ผ๋ก ํ์๋ ๊ฒฝ์ฐ์ ์ฑ ํ๋จ๋ฐ์ ๊ฒน์ณ ํ์๋๋ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ์ถํ ์ค๋ต๋ฐ๋ฅผ ์ ์ญ์ผ๋ก ํ์ํ๋ ๋ฑ์ ์กฐ์น๋ฅผ ํตํด ์ด๋ฅผ ์์ ํ๊ฒ ์ต๋๋ค.