Skip to content

Conversation

@JinUng41
Copy link
Collaborator

@JinUng41 JinUng41 commented Jun 24, 2025

👻 PULL REQUEST

📄 작업 내용

  • 투명도 내리기 및 신고하기와 관련된 액션 시트를 구현하고 적용하였습니다.
  • 일부 화면의 뷰모델 로직을 수정하였습니다.
구현 내용 IPhone 13 mini
투명도 내리기
신고하기

💻 주요 코드 설명

📍 WableTextSheetViewController와 사용법

  • 별도의 WableTextSheetViewController를 선언하였습니다.
    • 따로 구현한 이유는 기존의 액션 시트들과는 다른 성격을 가진다고 생각하였기 때문입니다.
  • 이 시트 역시 WableTextSheetShowable을 구현하여 비교적 사용하기 쉽게 하였습니다.
  • 그 중에서도 투명도 내리기는 취소 액션에 대해서 앰플리튜드 연결이 필요했기 때문에, onCancelonPrimary를 모두 인자로 받도록 하였습니다.
WableTextSheetShowable 코드
import UIKit

// MARK: - WableTextSheetShowable

protocol WableTextSheetShowable {
    func showWableTextSheet(title: String, placeholder: String, actions: WableTextSheetAction...)
    func showWableTextSheet(title: String, placeholder: String, actions: [WableTextSheetAction])
}

extension WableTextSheetShowable where Self: UIViewController {
    func showWableTextSheet(title: String, placeholder: String, actions: WableTextSheetAction...) {
        let wableTextSheet = WableTextSheetViewController(title: title, placeholder: placeholder)
        actions.forEach { wableTextSheet.addAction($0) }
        present(wableTextSheet, animated: true)
    }
    
    func showWableTextSheet(title: String, placeholder: String, actions: [WableTextSheetAction]) {
        let wableTextSheet = WableTextSheetViewController(title: title, placeholder: placeholder)
        wableTextSheet.addActions(actions)
        present(wableTextSheet, animated: true)
    }
    
    func showGhostSheet(onCancel cancelAction: (() -> Void)?, onPrimary primaryAction: @escaping (String?) -> Void) {
        let wableTextSheet = WableTextSheetViewController(
            title: StringLiterals.Ghost.sheetTitle,
            placeholder: StringLiterals.Ghost.sheetPlaceholder
        )
        let cancel = WableTextSheetAction(title: "고민할게요", style: .gray, handler: { _ in cancelAction?() })
        let confirm = WableTextSheetAction(title: "투명도 내리기", style: .primary, handler: primaryAction)
        wableTextSheet.addActions(cancel, confirm)
        present(wableTextSheet, animated: true)
    }
    
    func showReportSheet(onPrimary handler: @escaping (String?) -> Void) {
        let wableTextSheet = WableTextSheetViewController(
            title: StringLiterals.Report.sheetTitle,
            placeholder: StringLiterals.Report.sheetPlaceholder
        )
        let cancel = WableTextSheetAction(title: "고민할게요", style: .gray)
        let confirm = WableTextSheetAction(title: "신고하기", style: .primary, handler: handler)
        wableTextSheet.addActions(cancel, confirm)
        present(wableTextSheet, animated: true)
    }
}

// MARK: - UIViewController Extension

extension UIViewController: WableTextSheetShowable {}

📚 참고자료

  • 홈 및 글 상세 화면의 경우 각각 ViewitListViewController과 OtherProfileViewController를 참고하여 반영하시면 될 것 같습니다.

🔗 연결된 이슈

Summary by CodeRabbit

  • New Features

    • Introduced a customizable text input sheet for reporting and ghosting actions, allowing users to provide detailed reasons.
    • Added support for presenting bottom sheets and alerts with multiple actions using array-based interfaces.
    • Enhanced reporting and ghosting flows with new confirmation and input sheets, including improved placeholder guidance.
  • Improvements

    • Streamlined profile and content management actions with more intuitive, closure-based UI flows.
    • Refactored event handling to use Combine, improving responsiveness and maintainability.
    • Updated sheet and alert presentation logic for greater flexibility and consistency across the app.
    • Extended ghost actions to accept optional user-provided reasons.
    • Refined UI refresh control setup for better separation of concerns.
  • Bug Fixes

    • Improved keyboard handling and input validation in text input sheets.
  • Removals

    • Removed obsolete action kind enums and redundant sheet presentation methods.

@JinUng41 JinUng41 requested a review from youz2me June 24, 2025 06:28
@JinUng41 JinUng41 self-assigned this Jun 24, 2025
@JinUng41 JinUng41 added ✨ feat 기능 또는 객체 구현 🍻 진웅 술 한잔 가온나~ labels Jun 24, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jun 24, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This change removes the old ViewitBottomSheetActionKind enum and associated references, and introduces a new WableTextSheetViewController for modal text input, along with the WableTextSheetShowable protocol and helper methods. Reporting, banning, and ghosting flows are refactored to use these new components, with updated ViewModel and use case signatures to accept message/reason parameters.

Changes

File(s) / Path(s) Change Summary
.../project.pbxproj Removed ViewitBottomSheetActionKind.swift, added WableTextSheetViewController.swift and WableTextSheetShowable.swift to the project structure.
Core/Literals/String/StringLiterals+Ghost.swift
Core/Literals/String/StringLiterals+Report.swift
Added/updated static string constants for sheet placeholders and titles; removed sheetMessage in Report.
Domain/UseCase/Viewit/ReportViewitUseCase.swift report method now accepts a message parameter; uses it when reporting.
Domain/UseCase/Home/FetchGhostUseCase.swift execute method now accepts an optional reason parameter and passes it to repository call.
Presentation/Helper/UIAlertShowable.swift
WableBottomSheetShowable.swift
WableSheetShowable.swift
Added array-based overloads for showing alerts and sheets, enabling passing actions as arrays.
Presentation/Helper/WableTextSheetShowable.swift Added new protocol and default implementations for presenting a customizable text input sheet, with helper methods for ghost/report flows.
Presentation/Profile/Other/View/OtherProfileViewController.swift Refactored to use new sheet helpers and closure-based actions for reporting, banning, and ghosting; removed explicit presentXXXSheet methods.
Presentation/Profile/Other/ViewModel/OtherProfileViewModel.swift Updated reportContent/reportComment to accept nickname and message; ghostContent/ghostComment now accept a reason parameter.
Presentation/Viewit/List/Model/ViewitBottomSheetActionKind.swift Deleted file; removed enum ViewitBottomSheetActionKind.
Presentation/Viewit/List/View/Subview/ViewitListView.swift Refactored refresh control setup: now a property assigned in setupView().
Presentation/Viewit/List/View/ViewitListViewController.swift Replaced generic action relay with specific relays for report/ban/delete; switched to Combine for UI events; refactored bottom sheet logic to use new confirmation sheets and relays.
Presentation/Viewit/List/ViewModel/ViewitListViewModel.swift Refactored to use instance-level relays and modular binding methods for loading, reporting, deleting, banning; input/output structs updated to reflect new flows.
Presentation/WableComponent/ViewController/WableBottomSheetController.swift
WableSheetViewController.swift
Added addActions(_:) methods for adding multiple actions via arrays; marked init?(coder:) as unavailable in WableSheetViewController.
Presentation/WableComponent/ViewController/WableTextSheetViewController.swift Added new WableTextSheetViewController class for modal text input with customizable title, placeholder, and actions; includes input validation and keyboard handling.
Presentation/Home/View/HomeDetailViewController.swift Refactored reporting, banning, and ghosting flows to use new sheet helpers; updated ghost tap event to include optional message string.
Presentation/Home/View/HomeViewController.swift Refactored reporting, banning, and ghosting flows to use new sheet helpers; updated ghost tap event to include optional message string.
Presentation/Home/ViewModel/HomeDetailViewModel.swift Updated input type for ghost tapped item to include optional reason string; passed to use case.
Presentation/Home/ViewModel/HomeViewModel.swift Updated input type for ghost tapped item to include optional reason string; passed to use case.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ViewController
    participant WableTextSheetViewController
    participant ViewModel
    participant UseCase

    User->>ViewController: Tap "Report" or "Ghost" button
    ViewController->>WableTextSheetViewController: showReportSheet/showGhostSheet(...)
    WableTextSheetViewController->>User: Present text input modal
    User->>WableTextSheetViewController: Enter message/reason, tap Confirm
    WableTextSheetViewController->>ViewController: Call handler with input text
    ViewController->>ViewModel: reportContent/ghostContent(..., message/reason)
    ViewModel->>UseCase: report(..., message)/ghost(..., reason)
    UseCase-->>ViewModel: Result
    ViewModel-->>ViewController: Update UI/report success
Loading

Assessment against linked issues

Objective Addressed Explanation
변경된 투명도 내리기 및 신고하기 기능을 반영합니다. (#236)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Possibly related PRs

  • Team-Wable/WABLE-iOS#237: The main PR and the retrieved PR both involve removing the ViewitBottomSheetActionKind.swift file and adding the new WableTextSheetViewController.swift and WableTextSheetShowable.swift files, introducing a new text input sheet UI and related helper protocols and methods for reporting and transparency lowering features, indicating they modify the same project files and introduce the same new components and protocols.
  • Team-Wable/WABLE-iOS#217: The main PR extends the work introduced in the retrieved PR [Refactor] WableSheet 쉽게 사용하기 #217 by adding a new text input sheet component (WableTextSheetViewController) and a corresponding WableTextSheetShowable protocol with helper methods for presenting customizable text input sheets, building upon the previously introduced protocols (WableSheetShowable, WableBottomSheetShowable, and UIAlertShowable) for easier sheet and alert presentation; thus, the changes are directly related as they enhance and complement the same UI helper infrastructure for sheet presentation.

Suggested reviewers

  • youz2me

Poem

In the warren of code, a new sheet appears,
For ghosting and reporting, with input from peers.
Old enums are gone, new helpers abound,
With modals and closures, the actions are sound.
A hop and a tap, the user’s intent—
The rabbit approves, on progress content!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2806ff0 and 1c1c58f.

📒 Files selected for processing (2)
  • Wable-iOS.xcodeproj/project.pbxproj (6 hunks)
  • Wable-iOS/Core/Literals/String/StringLiterals+Ghost.swift (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (5)
Wable-iOS/Presentation/Helper/UIAlertShowable.swift (1)

24-28: Consider refactoring to reduce code duplication.

The implementation is correct, but there's code duplication between the variadic and array-based versions. Consider refactoring the variadic method to call the array-based version internally.

 func showAlert(title: String, message: String? = nil, actions: UIAlertAction...) {
-    let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
-    actions.forEach { alert.addAction($0) }
-    present(alert, animated: true)
+    showAlert(title: title, message: message, actions: Array(actions))
 }
Wable-iOS.xcodeproj/project.pbxproj (2)

729-730: Use explicit relative paths to guard against future file moves

Both PBXFileReference nodes specify only the filename. If someone later renames or moves the containing group, Xcode may silently lose the reference.
Safer long-term maintenance:

- path = WableTextSheetViewController.swift;
+ path = Presentation/WableComponent/ViewController/WableTextSheetViewController.swift;

Apply the same idea to WableTextSheetShowable.swift.


1869-1870: Group placement looks inconsistent

WableTextSheetViewController.swift is filed under the generic ViewController group, while its helper (WableTextSheetShowable.swift) lives under Helper.
Because this pair represents one reusable component, placing both under a dedicated sub-group (e.g. Presentation/Sheet) keeps the tree easier to navigate and avoids scattering related code.

Also applies to: 2045-2046

Wable-iOS/Presentation/WableComponent/ViewController/WableTextSheetViewController.swift (1)

65-65: Remove hardcoded placeholder strings from initialization.

These hardcoded strings are overridden in setupView(), but it's better to avoid them in initialization.

 private let titleLabel = UILabel().then {
-    $0.attributedText = "제목".pretendardString(with: .head1)
     $0.numberOfLines = 0
     $0.textAlignment = .center
 }
 private let placeholderLabel = UILabel().then {
-    $0.attributedText = "플레이스홀더".pretendardString(with: .body4)
     $0.textColor = .gray600
     $0.numberOfLines = 0
 }
 private let textCountLabel = UILabel().then {
-    $0.attributedText = "0/100".pretendardString(with: .caption4)
     $0.textAlignment = .right
 }

Also applies to: 78-79, 84-84

Wable-iOS/Presentation/Viewit/List/ViewModel/ViewitListViewModel.swift (1)

131-131: Consider extracting common error handling pattern.

The error handling pattern is repeated across multiple methods. Consider creating a helper to reduce duplication.

Add a helper method:

private func handleError<T>(_ error: WableError) -> AnyPublisher<T?, Never> {
    errorMessageRelay.send(error.localizedDescription)
    return .just(nil)
}

Then use it in the catch blocks:

-.catch { [weak owner] error -> AnyPublisher<Viewit?, Never> in
-    owner?.errorMessageRelay.send(error.localizedDescription)
-    return .just(nil)
-}
+.catch { [weak self] in self?.handleError($0) ?? .just(nil) }

Also applies to: 189-191, 210-212, 234-236

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42052e3 and e875841.

📒 Files selected for processing (17)
  • Wable-iOS.xcodeproj/project.pbxproj (6 hunks)
  • Wable-iOS/Core/Literals/String/StringLiterals+Ghost.swift (1 hunks)
  • Wable-iOS/Core/Literals/String/StringLiterals+Report.swift (1 hunks)
  • Wable-iOS/Domain/UseCase/Viewit/ReportViewitUseCase.swift (1 hunks)
  • Wable-iOS/Presentation/Helper/UIAlertShowable.swift (2 hunks)
  • Wable-iOS/Presentation/Helper/WableBottomSheetShowable.swift (2 hunks)
  • Wable-iOS/Presentation/Helper/WableSheetShowable.swift (2 hunks)
  • Wable-iOS/Presentation/Helper/WableTextSheetShowable.swift (1 hunks)
  • Wable-iOS/Presentation/Profile/Other/View/OtherProfileViewController.swift (2 hunks)
  • Wable-iOS/Presentation/Profile/Other/ViewModel/OtherProfileViewModel.swift (3 hunks)
  • Wable-iOS/Presentation/Viewit/List/Model/ViewitBottomSheetActionKind.swift (0 hunks)
  • Wable-iOS/Presentation/Viewit/List/View/Subview/ViewitListView.swift (2 hunks)
  • Wable-iOS/Presentation/Viewit/List/View/ViewitListViewController.swift (7 hunks)
  • Wable-iOS/Presentation/Viewit/List/ViewModel/ViewitListViewModel.swift (3 hunks)
  • Wable-iOS/Presentation/WableComponent/ViewController/WableBottomSheetController.swift (1 hunks)
  • Wable-iOS/Presentation/WableComponent/ViewController/WableSheetViewController.swift (3 hunks)
  • Wable-iOS/Presentation/WableComponent/ViewController/WableTextSheetViewController.swift (1 hunks)
💤 Files with no reviewable changes (1)
  • Wable-iOS/Presentation/Viewit/List/Model/ViewitBottomSheetActionKind.swift
🔇 Additional comments (37)
Wable-iOS/Core/Literals/String/StringLiterals+Ghost.swift (1)

17-20: LGTM! Well-formatted multiline string constant.

The multiline string constant is properly formatted and the content aligns with the transparency lowering feature implementation.

Wable-iOS/Presentation/Helper/UIAlertShowable.swift (1)

14-14: LGTM! Useful array-based overload.

The new method declaration provides a convenient alternative for passing actions as an array.

Wable-iOS/Presentation/WableComponent/ViewController/WableBottomSheetController.swift (1)

105-107: LGTM! Clean and consistent implementation.

The array-based method provides a useful alternative to the variadic version and follows the established patterns in the codebase.

Wable-iOS/Presentation/Viewit/List/View/Subview/ViewitListView.swift (2)

21-21: LGTM! Good separation of concerns.

Extracting the refresh control as a separate property improves code organization and accessibility.


57-57: LGTM! Clean assignment in setup method.

The explicit assignment in setupView() makes the refresh control configuration more explicit and maintainable.

Wable-iOS/Presentation/Helper/WableBottomSheetShowable.swift (2)

14-14: LGTM! Useful array-based overload.

The new method declaration provides a convenient alternative for passing actions as an array, consistent with similar patterns in other helper protocols.


24-28: LGTM! Efficient implementation using the new array-based method.

The implementation efficiently uses the new addActions(actions) method from WableBottomSheetController, providing a cleaner and more direct approach compared to the variadic version.

Wable-iOS/Core/Literals/String/StringLiterals+Report.swift (1)

16-21: LGTM! String updates align well with the new text input sheet.

The changes improve the user experience by:

  • Making the title more direct ("신고하기" vs the previous question form)
  • Providing clear guidance through the placeholder text about optional reporting reasons
  • Using proper multiline string formatting

The Korean text is well-written and user-friendly.

Wable-iOS/Presentation/Helper/WableSheetShowable.swift (2)

14-14: LGTM! Protocol method addition provides useful flexibility.

The array-based overload complements the existing variadic method, allowing callers to pass pre-constructed action arrays when needed.


24-28: LGTM! Implementation correctly mirrors the variadic version.

The implementation properly:

  • Creates the WableSheetViewController with title and message
  • Uses the addActions(actions) method to add all actions at once
  • Maintains consistent presentation behavior with the existing method
Wable-iOS.xcodeproj/project.pbxproj (2)

359-360: Check target membership for the two new BuildFile entries

WableTextSheetViewController.swift and WableTextSheetShowable.swift are correctly created as PBXBuildFile objects, but they’re currently added only to the main Wable-iOS target.
If your project has unit-test / snapshot-test targets that import presentation-layer code, remember to tick these two files there as well; otherwise compilation will fail when the tests run on CI.


2676-2676: Verify no duplicate “Compile Sources” entries

The two new build files appear once each in PBXSourcesBuildPhase, which is correct. If you notice duplicate warnings in Xcode (“file listed twice”), remove one of the entries to avoid slow incremental builds.

Also applies to: 2810-2810

Wable-iOS/Domain/UseCase/Viewit/ReportViewitUseCase.swift (2)

12-12: LGTM! Enhanced flexibility for custom report messages.

The updated protocol signature allows callers to provide custom report messages while maintaining the existing functionality.


19-24: LGTM! Proper fallback logic implemented.

The implementation correctly uses the provided message when available, falling back to the original viewit text when the message is empty. This maintains backward compatibility while enabling the new custom message functionality.

Wable-iOS/Presentation/WableComponent/ViewController/WableSheetViewController.swift (2)

100-103: LGTM! Properly prevents unwanted initialization.

Marking the NSCoder initializer as unavailable is a good practice for view controllers that should only be initialized programmatically.


121-127: LGTM! Consistent API design with both array and variadic support.

The addition of the array-based addActions method provides flexibility for dynamic action creation while maintaining the existing variadic method for convenience.

Wable-iOS/Presentation/Profile/Other/ViewModel/OtherProfileViewModel.swift (4)

128-137: LGTM! Improved API design with explicit parameters.

The refactored method signature removes internal lookup logic and makes the required parameters explicit. This improves separation of concerns and makes the method's dependencies clearer.


139-148: LGTM! Consistent refactoring applied to comment reporting.

The same improvement pattern is correctly applied to comment reporting, maintaining consistency across the API.


184-199: LGTM! Enhanced ghosting functionality with reason parameter.

Adding the reason parameter allows for more detailed ghosting reports while maintaining the existing functionality through direct parameter passing.


201-216: LGTM! Consistent ghosting API for comments.

The comment ghosting method follows the same improved pattern as content ghosting, maintaining API consistency.

Wable-iOS/Presentation/Helper/WableTextSheetShowable.swift (5)

12-15: LGTM! Well-designed protocol with flexible overloads.

The protocol provides both variadic and array-based method signatures, offering flexibility for different usage patterns while maintaining a clean interface.


17-28: LGTM! Clean default implementation.

The default implementation properly creates and presents the text sheet, with the array version correctly utilizing the new addActions method from WableTextSheetViewController.


30-39: LGTM! Convenient ghosting sheet with proper callback handling.

The showGhostSheet method provides a reusable way to present ghosting UI with customizable cancel and primary actions. The closure-based approach allows for flexible callback handling.


41-51: LGTM! Consistent reporting sheet implementation.

The showReportSheet method follows the same pattern as the ghost sheet, providing consistency in the UI flow for reporting functionality.


55-55: LGTM! Convenient protocol adoption for all view controllers.

Extending UIViewController to conform to the protocol makes the functionality available throughout the app without requiring explicit conformance declarations.

Wable-iOS/Presentation/Profile/Other/View/OtherProfileViewController.swift (5)

221-232: LGTM! Effective integration of new reporting flow.

The refactored content reporting uses the new showReportSheet method with a closure that properly passes the author nickname and message (with fallback to content text) to the view model. The user role check is correctly preserved.


234-244: LGTM! Proper banning flow with confirmation sheet.

The banning functionality correctly uses showWableSheetWithCancel for confirmation and maintains the admin-only restriction.


247-255: LGTM! Well-implemented ghosting flow with analytics.

The ghosting implementation properly uses showGhostSheet with separate cancel and primary callbacks, includes appropriate analytics tracking, and passes the reason with an empty string fallback.


267-292: LGTM! Consistent comment handling patterns.

The comment reporting and banning logic correctly mirrors the content handling patterns, maintaining consistency across the UI while using the appropriate comment-specific view model methods.


294-302: LGTM! Complete comment ghosting implementation.

The comment ghosting follows the same effective pattern as content ghosting, with proper analytics tracking and reason parameter handling.

Wable-iOS/Presentation/WableComponent/ViewController/WableTextSheetViewController.swift (2)

16-46: LGTM! Well-structured action model.

The WableTextSheetAction struct and its Style extension are properly designed with clear separation of concerns.


229-229: Verify custom SnapKit extension method.

The adjustedHeightEqualTo method is not part of standard SnapKit. Please ensure this custom extension is properly defined in the codebase.

#!/bin/bash
# Description: Search for the definition of adjustedHeightEqualTo extension method

# Search for the adjustedHeightEqualTo method definition
ast-grep --pattern 'func adjustedHeightEqualTo($$$) { $$$ }'

# Also search with ripgrep as backup
rg -A 5 'adjustedHeightEqualTo' --type swift

Also applies to: 245-245

Wable-iOS/Presentation/Viewit/List/View/ViewitListViewController.swift (3)

36-38: LGTM! Clear separation of action relays.

The distinct relays for report, ban, and delete actions provide better type safety and clearer intent than the previous generic approach.


153-164: Great use of Combine for UI event handling.

The migration from target-action to Combine publishers improves code consistency and makes the reactive flow clearer.


268-294: Well-structured confirmation sheet methods.

The showDeleteConfirmationSheet and showBanConfirmationSheet methods are cleanly implemented with appropriate titles and actions.

Wable-iOS/Presentation/Viewit/List/ViewModel/ViewitListViewModel.swift (2)

18-24: Excellent refactoring with improved modularity.

The separation of binding logic into dedicated methods and the use of instance-level relays greatly improves code organization and testability.

Also applies to: 64-79


176-198: LGTM! Proper report handling with message parameter.

The bindReport method correctly handles the report flow with user-provided message and includes appropriate error handling.

Comment on lines +141 to +155
private func createWableButton(for action: WableTextSheetAction) -> WableButton {
return WableButton(style: action.style.buttonStyle).then {
var config = $0.configuration ?? .filled()
config.attributedTitle = action.title.pretendardString(with: .body1)
$0.configuration = config

let action = UIAction { [weak self] _ in
self?.dismiss(animated: true) {
action.handler?(self?.messageTextView.text)
}
}

$0.addAction(action, for: .touchUpInside)
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix variable shadowing in createWableButton method.

The action variable in the UIAction closure shadows the method parameter, which could lead to confusion.

 private func createWableButton(for action: WableTextSheetAction) -> WableButton {
     return WableButton(style: action.style.buttonStyle).then {
         var config = $0.configuration ?? .filled()
         config.attributedTitle = action.title.pretendardString(with: .body1)
         $0.configuration = config
         
-        let action = UIAction { [weak self] _ in
+        let buttonAction = UIAction { [weak self] _ in
             self?.dismiss(animated: true) {
                 action.handler?(self?.messageTextView.text)
             }
         }
         
-        $0.addAction(action, for: .touchUpInside)
+        $0.addAction(buttonAction, for: .touchUpInside)
     }
 }
📝 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.

Suggested change
private func createWableButton(for action: WableTextSheetAction) -> WableButton {
return WableButton(style: action.style.buttonStyle).then {
var config = $0.configuration ?? .filled()
config.attributedTitle = action.title.pretendardString(with: .body1)
$0.configuration = config
let action = UIAction { [weak self] _ in
self?.dismiss(animated: true) {
action.handler?(self?.messageTextView.text)
}
}
$0.addAction(action, for: .touchUpInside)
}
}
private func createWableButton(for action: WableTextSheetAction) -> WableButton {
return WableButton(style: action.style.buttonStyle).then {
var config = $0.configuration ?? .filled()
config.attributedTitle = action.title.pretendardString(with: .body1)
$0.configuration = config
let buttonAction = UIAction { [weak self] _ in
self?.dismiss(animated: true) {
action.handler?(self?.messageTextView.text)
}
}
$0.addAction(buttonAction, for: .touchUpInside)
}
}
🤖 Prompt for AI Agents
In
Wable-iOS/Presentation/WableComponent/ViewController/WableTextSheetViewController.swift
between lines 141 and 155, the UIAction closure defines a variable named
'action' that shadows the method parameter 'action', causing confusion. Rename
the closure's 'action' variable to a different name, such as 'uiAction', to
avoid shadowing and clarify the code.

Comment on lines +245 to +247
self?.showReportSheet(onPrimary: { message in
self?.reportRelay.send(message ?? "")
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Handle report cancellation properly.

Sending an empty string when the user cancels might trigger an unnecessary API call. Consider only sending when the user provides actual input.

 self?.showReportSheet(onPrimary: { message in
-    self?.reportRelay.send(message ?? "")
+    if let message = message, !message.isEmpty {
+        self?.reportRelay.send(message)
+    }
 })

Also applies to: 260-262

🤖 Prompt for AI Agents
In Wable-iOS/Presentation/Viewit/List/View/ViewitListViewController.swift around
lines 245 to 247 and similarly at 260 to 262, the code sends an empty string to
reportRelay when the user cancels the report, which may cause unnecessary API
calls. Modify the closure to check if the message is non-nil and non-empty
before calling reportRelay.send, ensuring that only valid user input triggers
the send action.

errorMessageRelay.send(error.localizedDescription)
.flatMap { owner, data -> AnyPublisher<Viewit?, Never> in
let (index, message) = data
let viewit = owner.viewitListRelay.value[index]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add bounds checking to prevent potential crash.

Direct array access without bounds checking could cause crashes if the list changes between meatball tap and action execution.

Add safety checks before accessing the array:

 let (index, message) = data
+guard index < owner.viewitListRelay.value.count else { return .just(nil) }
 let viewit = owner.viewitListRelay.value[index]

Apply similar checks in bindDelete and bindBan methods.

Also applies to: 208-208, 232-232

🤖 Prompt for AI Agents
In Wable-iOS/Presentation/Viewit/List/ViewModel/ViewitListViewModel.swift at
lines 187, 208, and 232, the code directly accesses the viewitListRelay array by
index without checking if the index is within bounds, which can cause crashes if
the list changes. Add conditional checks to verify the index is valid before
accessing the array element in these lines, and apply the same bounds checking
in the bindDelete and bindBan methods to prevent out-of-range errors.

Copy link
Member

@youz2me youz2me left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good. 고생많으셨습니다!

@github-project-automation github-project-automation bot moved this to In Review in Wable-iOS Jun 24, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e875841 and 2806ff0.

📒 Files selected for processing (6)
  • Wable-iOS/Domain/UseCase/Home/FetchGhostUseCase.swift (1 hunks)
  • Wable-iOS/Presentation/Home/View/HomeDetailViewController.swift (7 hunks)
  • Wable-iOS/Presentation/Home/View/HomeViewController.swift (3 hunks)
  • Wable-iOS/Presentation/Home/ViewModel/HomeDetailViewModel.swift (2 hunks)
  • Wable-iOS/Presentation/Home/ViewModel/HomeViewModel.swift (2 hunks)
  • Wable-iOS/Presentation/Profile/Other/View/OtherProfileViewController.swift (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Wable-iOS/Presentation/Profile/Other/View/OtherProfileViewController.swift
🔇 Additional comments (10)
Wable-iOS/Domain/UseCase/Home/FetchGhostUseCase.swift (1)

23-29: LGTM!

The addition of the optional reason parameter is implemented correctly, with proper nil handling that defaults to an empty string.

Wable-iOS/Presentation/Home/ViewModel/HomeViewModel.swift (1)

49-49: LGTM!

The changes correctly propagate the optional ghost reason from the input publisher to the use case execution.

Also applies to: 197-203

Wable-iOS/Presentation/Home/ViewModel/HomeDetailViewModel.swift (1)

70-70: LGTM!

The changes correctly handle the optional ghost reason parameter in the view model's input and properly forward it to the use case.

Also applies to: 303-309

Wable-iOS/Presentation/Home/View/HomeViewController.swift (4)

36-36: LGTM!

The subject type correctly includes the optional message parameter for ghost actions.


223-241: Well-structured refactoring!

The refactoring to use showReportSheet and showBottomSheet helper methods improves code readability and maintainability for admin users.


243-258: Clean implementation!

The report action for non-admin users properly uses the new helper method with appropriate callbacks.


290-297: Excellent ghost sheet implementation!

The ghost action properly handles both cancel and primary actions, correctly passing the optional message to the subject and tracking appropriate Amplitude events.

Wable-iOS/Presentation/Home/View/HomeDetailViewController.swift (3)

43-43: LGTM!

The subject type correctly includes the optional message parameter and PostType for ghost actions.


324-331: Well-implemented ghost sheet!

The ghost action for content properly tracks events and passes the optional message with the correct PostType.


461-468: Clean ghost implementation for comments!

The ghost action for comments follows the same pattern as content, maintaining consistency across the codebase.

Comment on lines +276 to +294
let reportAction = WableBottomSheetAction(title: "신고하기") { [weak self] in
self?.showReportSheet(
onPrimary: { message in
viewController.dismiss(
animated: true,
completion: {
viewController.dismiss(
animated: true,
completion: {
self?.didReportTappedSubject.send(
(
item.content.contentInfo.author.nickname,
message ?? item.content.contentInfo.text
)
)
})
}
)
)

self.present(viewController, animated: true)
})
}))
})
})
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix duplicate dismiss calls

There are nested viewController.dismiss calls which could cause unexpected behavior. The outer dismiss at line 283 appears to be redundant.

 let reportAction = WableBottomSheetAction(title: "신고하기") { [weak self] in
     self?.showReportSheet(
         onPrimary: { message in
             viewController.dismiss(
                 animated: true,
                 completion: {
-                    viewController.dismiss(
-                        animated: true,
-                        completion: {
-                            self?.didReportTappedSubject.send(
-                                (
-                                    item.content.contentInfo.author.nickname,
-                                    message ?? item.content.contentInfo.text
-                                )
-                            )
-                    })
+                    self?.didReportTappedSubject.send(
+                        (
+                            item.content.contentInfo.author.nickname,
+                            message ?? item.content.contentInfo.text
+                        )
+                    )
                 })
         })
 }
🤖 Prompt for AI Agents
In Wable-iOS/Presentation/Home/View/HomeDetailViewController.swift between lines
276 and 294, there are nested calls to viewController.dismiss which can cause
unexpected behavior. Remove the outer dismiss call at line 283 and keep only the
inner dismiss call to ensure the view controller is dismissed once before
triggering the didReportTappedSubject event.

@JinUng41 JinUng41 merged commit 5f0694d into develop Jun 24, 2025
@JinUng41 JinUng41 deleted the feat/#236-ghost-report branch June 24, 2025 16:20
@github-project-automation github-project-automation bot moved this from In Review to Done in Wable-iOS Jun 24, 2025
youz2me pushed a commit that referenced this pull request Oct 26, 2025
[Feat] 투명도 내리기 및 신고하기 기능 구현
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ feat 기능 또는 객체 구현 🍻 진웅 술 한잔 가온나~

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[작업 태그] 투명도 내리기 및 신고 기능 구현

3 participants