Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// MissionCard.swift
// Cherrish-iOS
//
// Created by sumin Kong on 1/11/26.
//

import SwiftUI

struct MissionCard: View {
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

접근 제어자를 명시적으로 선언하세요.

SelectionChip과 마찬가지로, 재사용 가능한 컴포넌트의 접근 수준을 명확히 하기 위해 public 또는 internal을 명시적으로 선언하세요.

♻️ 제안하는 수정
-struct MissionCard: View {
+public struct MissionCard: View {
📝 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
struct MissionCard: View {
public struct MissionCard: View {
🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/MissionCard.swift
at line 10, The MissionCard view lacks an explicit access control modifier;
update the struct declaration for MissionCard to include the intended access
level (e.g., public or internal) to match the convention used for reusable
components like SelectionChip, and ensure any related nested types/properties
used externally also have appropriate access modifiers so the component’s
visibility is consistent.


let missionText: String
@Binding var isSelected: Bool

var body: some View {
VStack(alignment: .leading) {

HStack {
Spacer()
Image(isSelected ? "radiobtn_selected" : "radiobtn_default")
}

Spacer()

Text(missionText)
.typography(.body1_m_14)
.foregroundStyle(isSelected ? .gray800 : .gray700)
.padding(.leading, 8)
.padding(.bottom, 6)
}
.padding(.horizontal, 7)
.padding(.vertical, 6)
.frame(width: 148, height: 80)
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

SelectionChip과 동일한 고정 크기 프레임 문제.

SelectionChip과 동일한 프레임 크기(148x80)를 사용하고 있습니다. 디자인 요구사항을 확인하고, 두 컴포넌트가 동일한 크기를 공유해야 한다면 상수로 추출하여 중복을 제거하는 것을 고려하세요.

🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/MissionCard.swift
at line 33, MissionCard currently hardcodes .frame(width: 148, height: 80) which
duplicates SelectionChip; extract a shared constant (e.g., let sharedCardSize =
CGSize(width: 148, height: 80) or a CGFloat constants CARD_WIDTH / CARD_HEIGHT)
and replace the hardcoded .frame call in MissionCard with .frame(width:
sharedCardSize.width, height: sharedCardSize.height); also update SelectionChip
to use the same constant so both components share one source of truth and remove
duplication.

.background(isSelected ? .red200 : .gray0)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(isSelected ? .red500 : .gray500, lineWidth: 1)
)
.onTapGesture {
isSelected.toggle()
}
Comment on lines +35 to +41
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

SelectionChip과 코드 중복이 있습니다.

MissionCardSelectionChip의 배경, 테두리, 탭 제스처 로직이 거의 동일합니다. 공통 로직을 추출하여 재사용 가능한 modifier나 base component로 만드는 것을 고려하세요.

♻️ 제안하는 리팩토링 예시

공통 스타일을 ViewModifier로 추출:

struct SelectableChipStyle: ViewModifier {
    let isSelected: Bool
    
    func body(content: Content) -> some View {
        content
            .frame(width: 148, height: 80)
            .background(isSelected ? .red200 : .gray0)
            .cornerRadius(10)
            .overlay(
                RoundedRectangle(cornerRadius: 10)
                    .stroke(isSelected ? .red500 : .gray500, lineWidth: 1)
            )
    }
}

extension View {
    func selectableChipStyle(isSelected: Bool) -> some View {
        modifier(SelectableChipStyle(isSelected: isSelected))
    }
}

그런 다음 각 컴포넌트에서 사용:

// MissionCard에서
var body: some View {
    VStack(alignment: .leading) {
        // ... content
    }
    .selectableChipStyle(isSelected: isSelected)
    .onTapGesture {
        isSelected.toggle()
    }
}
🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/MissionCard.swift
around lines 35 - 41, MissionCard duplicates SelectionChip UI and tap logic;
extract the shared styling into a reusable ViewModifier (e.g.,
SelectableChipStyle) and a convenience extension (e.g.,
selectableChipStyle(isSelected:)), then replace the duplicated
background/cornerRadius/overlay code in MissionCard and SelectionChip with
.selectableChipStyle(isSelected: isSelected) while keeping the .onTapGesture {
isSelected.toggle() } where selection state is handled; ensure the modifier
accepts isSelected to switch colors and corner radius consistently across both
components.

Comment on lines +39 to +41
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

접근성 지원을 추가하세요.

SelectionChip과 마찬가지로, VoiceOver 사용자를 위한 접근성 레이블과 힌트가 필요합니다. 라디오 버튼 동작을 수행하는 경우 .accessibilityAddTraits(.isButton)도 고려하세요.

♻️ 제안하는 수정
         .onTapGesture {
             isSelected.toggle()
         }
+        .accessibilityLabel(missionText)
+        .accessibilityAddTraits(isSelected ? [.isButton, .isSelected] : .isButton)
+        .accessibilityHint("미션 카드를 선택하려면 탭하세요")
     }
📝 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
.onTapGesture {
isSelected.toggle()
}
.onTapGesture {
isSelected.toggle()
}
.accessibilityLabel(missionText)
.accessibilityAddTraits(isSelected ? [.isButton, .isSelected] : .isButton)
.accessibilityHint("미션 카드를 선택하려면 탭하세요")
🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/MissionCard.swift
around lines 39 - 41, Add VoiceOver support to the MissionCard by attaching an
accessibility label and hint and exposing its selectable state: use the existing
isSelected toggle (from the onTapGesture) to set .accessibilityLabel("...") and
.accessibilityHint("...") with context-specific text, add
.accessibilityAddTraits(.isButton) and conditionally add the selected trait when
isSelected (e.g., .accessibilityAddTraits(isSelected ? .isSelected : [])), and
implement .accessibilityAction { isSelected.toggle() } so screen reader users
can both hear the state and perform the same toggle action (follow the pattern
used in SelectionChip for wording and trait choices).

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// SelectionChip.swift
// Cherrish-iOS
//
// Created by sumin Kong on 1/11/26.
//

import SwiftUI

struct SelectionChip: View {
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

접근 제어자를 명시적으로 선언하세요.

컴포넌트의 접근 제어자가 명시되지 않아 기본적으로 internal이 적용됩니다. Global/Components 디렉토리에 있는 재사용 가능한 컴포넌트이므로, 의도된 접근 수준을 명확히 하기 위해 public 또는 internal을 명시적으로 선언하는 것이 좋습니다.

♻️ 제안하는 수정
-struct SelectionChip: View {
+public struct SelectionChip: View {
📝 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
struct SelectionChip: View {
public struct SelectionChip: View {
🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/SelectionChip.swift
at line 10, The SelectionChip view has no explicit access control (defaults to
internal); update the declaration for struct SelectionChip to the intended
visibility (e.g., prepend public if it should be reusable across modules) and
explicitly annotate any stored properties, initializers, and methods inside
SelectionChip (and related nested types) with public or internal as appropriate
so the component's API surface is clear and consistent.


let title: String
@Binding var isSelected: Bool

var body: some View {
Text(title)
.typography(.body1_m_14)
.foregroundStyle(isSelected ? .gray800 : .gray700)
.frame(width: 148, height: 80)
.background(isSelected ? .red200 : .gray0)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(isSelected ? .red500 : .gray500, lineWidth: 1)
)
.onTapGesture {
isSelected.toggle()
}
Comment on lines +25 to +27
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

접근성 지원을 추가하세요.

컴포넌트에 접근성 레이블과 힌트가 없어 VoiceOver 사용자가 컴포넌트의 상태와 목적을 이해하기 어렵습니다.

♻️ 제안하는 수정
         .onTapGesture {
             isSelected.toggle()
         }
+        .accessibilityLabel(title)
+        .accessibilityAddTraits(isSelected ? .isSelected : [])
+        .accessibilityHint("탭하여 선택 상태를 전환합니다")
     }
📝 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
.onTapGesture {
isSelected.toggle()
}
.onTapGesture {
isSelected.toggle()
}
.accessibilityLabel(title)
.accessibilityAddTraits(isSelected ? .isSelected : [])
.accessibilityHint("탭하여 선택 상태를 전환합니다")
🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/SelectionChip.swift
around lines 28 - 30, The SelectionChip view lacks VoiceOver metadata; update
the component (SelectionChip) to expose its role, state and action by adding
accessibility modifiers: set a descriptive accessibilityLabel (e.g., the chip
title), an accessibilityValue that reflects isSelected ("selected"/"not
selected"), and an accessibilityHint describing the tap action; also add an
accessibilityAddTraits(.isButton) (and .isSelected when isSelected == true) and
implement an accessibilityAction that performs the same logic as the
onTapGesture (the isSelected.toggle() behavior) so VoiceOver users can
understand and invoke the control.

}
}