Design/#49 - 사이드바 디자인 수정 및 온보딩/잠금 화면 구현 - #50
Conversation
Walkthrough온보딩 및 잠금 화면을 TCA 기반으로 추가하고, Lottie 애니메이션과 관련 의존성을 연결했습니다. 사이드바에 Notice 필터와 아이콘 색상을 반영했으며, 공통 디자인 컴포넌트와 화면 배경 처리를 확장했습니다. Changes프레젠테이션 디자인 및 화면 플로우
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant OnboardingView
participant OnboardingFeature
participant LottieView
participant DotLottieFile
OnboardingView->>OnboardingFeature: 단계별 버튼 액션 전송
OnboardingFeature->>OnboardingFeature: 온보딩 단계 전환
OnboardingView->>LottieView: progress 애니메이션 표시
LottieView->>DotLottieFile: progress 리소스 비동기 로드
DotLottieFile-->>LottieView: Lottie 파일 반환
OnboardingFeature-->>OnboardingView: completed delegate 전달
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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.
Actionable comments posted: 5
🧹 Nitpick comments (3)
Projects/DVDesign/Sources/Components/DVButton.swift (1)
14-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win레이아웃 계산 프로퍼티의 노출 범위를 줄이세요.
cornerRadius,height,horizontalPadding,width,font는DVButtonStyle에서만 사용되므로fileprivate로 제한해 모듈 API 노출을 줄이는 편이 좋습니다. As per path instructions, “접근 제어가 가능한 가장 엄격한 수준인지 확인하세요. (private>fileprivate>internal)”.🤖 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 `@Projects/DVDesign/Sources/Components/DVButton.swift` around lines 14 - 46, Update the cornerRadius, height, horizontalPadding, width, and font properties on DVButtonStyle to use fileprivate access, keeping them available to DVButtonStyle usage while reducing their exposure from the current default scope.Source: Path instructions
Projects/DVDesign/Sources/Foundations/Color/View+DVColor.swift (1)
14-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
public extension대신 메서드별 접근 제어를 사용하세요.이 메서드를 추가하면서
View의 모든 확장 멤버가 public이 됩니다.extension View로 바꾸고 필요한 메서드에만public을 직접 선언하세요.수정 예시
-public extension View { - func dvForegroundColor(_ token: DVColor) -> some View { +extension View { + public func dvForegroundColor(_ token: DVColor) -> some View { self.foregroundStyle(token.color) } - func dvBackgroundColor(_ token: DVColor) -> some View { + public func dvBackgroundColor(_ token: DVColor) -> some View { self.background(token.color) } - func dvScreenBackground(_ token: DVColor = .gray100) -> some View { + public func dvScreenBackground(_ token: DVColor = .gray100) -> some View { self.background(token.color.ignoresSafeArea()) } }As per path instructions, “
public extension패턴 대신 각 선언에 직접 접근 제어가 명시되어 있는지 확인하세요.”🤖 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 `@Projects/DVDesign/Sources/Foundations/Color/View`+DVColor.swift around lines 14 - 16, Replace the public extension around dvScreenBackground with a non-public extension View, then explicitly mark only dvScreenBackground as public. Ensure no other View extension members become public implicitly.Source: Path instructions
Projects/DVPresentation/Sources/Features/Lock/LockView.swift (1)
14-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winStore의 공개 가변 API와 불필요한
@Bindable을 줄이세요.현재 뷰는
$store바인딩을 사용하지 않고 상태 조회와send만 수행하므로@Bindable public var store가 필요하지 않습니다.private let store: StoreOf<LockFeature>로 변경해 외부의 Store 재할당과 불필요한 API 노출을 막으세요.As per path instructions: 접근 제어가 가능한 가장 엄격한 수준인지 확인하세요.
🤖 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 `@Projects/DVPresentation/Sources/Features/Lock/LockView.swift` at line 14, LockView의 store 선언에서 불필요한 `@Bindable과` public 가변성을 제거하고, 상태 조회와 send 호출에 맞게 private let store: StoreOf<LockFeature>로 변경하세요.Source: Path instructions
🤖 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 `@Projects/DVPresentation/Sources/Features/Lock/LockFeature.swift`:
- Around line 49-50: LockFeature의 didTapUnlock 처리에서 즉시 unlockCompleted를 보내지 말고
LocalUserAuthenticationServiceImpl 의존성을 주입해 authenticate를 호출하세요. 인증 성공 결과에서만
delegate unlockCompleted를 전송하고, 실패·취소·미지원 결과는 잠금 상태를 유지하거나 기존 에러 전달 경로로 처리하세요.
In `@Projects/DVPresentation/Sources/Features/Onboarding/OnboardingFeature.swift`:
- Around line 75-77: Update the didTapEnableTouchID handling in
OnboardingFeature so it advances to .icloudSync only after the authentication
client’s success callback or the parent delegate’s success event is received.
Keep the current step unchanged and avoid emitting the transition for canceled
or failed Touch ID attempts.
- Around line 82-87: Connect the actual synchronization client to the
didTapEnableSync case, dispatching syncingCompleted only after a successful sync
so the existing completed delegate is reached. Handle synchronization failures
by updating the appropriate failure state and provide the retry path from the
syncing flow, using the feature’s existing TCA dependency and action/state
symbols.
- Around line 31-38: Update the currentStepIndex computed property so the
.syncing case returns index 3, making it the fourth indicator step while
preserving the existing indices for .welcome, .security, and .icloudSync.
In `@Projects/DVPresentation/Sources/Features/Sidebar/SidebarView.swift`:
- Around line 183-184: Change the extension containing SidebarFilter.iconColor
from private to fileprivate so SidebarView can access the property within the
same file while keeping its visibility as narrow as possible.
---
Nitpick comments:
In `@Projects/DVDesign/Sources/Components/DVButton.swift`:
- Around line 14-46: Update the cornerRadius, height, horizontalPadding, width,
and font properties on DVButtonStyle to use fileprivate access, keeping them
available to DVButtonStyle usage while reducing their exposure from the current
default scope.
In `@Projects/DVDesign/Sources/Foundations/Color/View`+DVColor.swift:
- Around line 14-16: Replace the public extension around dvScreenBackground with
a non-public extension View, then explicitly mark only dvScreenBackground as
public. Ensure no other View extension members become public implicitly.
In `@Projects/DVPresentation/Sources/Features/Lock/LockView.swift`:
- Line 14: LockView의 store 선언에서 불필요한 `@Bindable과` public 가변성을 제거하고, 상태 조회와 send
호출에 맞게 private let store: StoreOf<LockFeature>로 변경하세요.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: a7537cc9-5e7c-46c5-a167-e0c6b984d53c
📒 Files selected for processing (15)
Projects/DVDesign/Resources/progress.lottieProjects/DVDesign/Sources/Components/DVButton.swiftProjects/DVDesign/Sources/Components/DVCategory.swiftProjects/DVDesign/Sources/Components/DVStepIndicator.swiftProjects/DVDesign/Sources/Foundations/Color/View+DVColor.swiftProjects/DVPresentation/Project.swiftProjects/DVPresentation/Sources/Features/Lock/LockFeature.swiftProjects/DVPresentation/Sources/Features/Lock/LockView.swiftProjects/DVPresentation/Sources/Features/Main/MainView.swiftProjects/DVPresentation/Sources/Features/Onboarding/OnboardingFeature.swiftProjects/DVPresentation/Sources/Features/Onboarding/OnboardingView.swiftProjects/DVPresentation/Sources/Features/Sidebar/SidebarFeature.swiftProjects/DVPresentation/Sources/Features/Sidebar/SidebarView.swiftTuist/Package.swiftTuist/ProjectDescriptionHelpers/TargetDependency+External.swift
| case .didTapUnlock: | ||
| return .send(.delegate(.unlockCompleted)) |
There was a problem hiding this comment.
🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Repo files matching LockFeature.swift:"
fd -a 'LockFeature\.swift$' . | sed 's#^\./##'
file="$(fd 'LockFeature\.swift$' . | head -n1)"
if [ -n "${file:-}" ]; then
echo
echo "File: $file"
wc -l "$file"
echo
echo "Outline:"
ast-grep outline "$file" || true
echo
echo "Relevant source:"
sed -n '1,180p' "$file" | cat -n
fi
echo
echo "Search for unlockCompleted and delegate usages:"
rg -n "unlockCompleted|didTapUnlock|unlockRequested|delegate\(" . -g '*.swift' | head -n 200Repository: DevaultProject/Devault-macOS
Length of output: 3801
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "LockView.swift:"
sed -n '1,160p' ./Projects/DVPresentation/Sources/Features/Lock/LockView.swift | cat -n
echo
echo "Files containing LockFeature / lock references:"
rg -n "LockFeature|\\bunlockCompleted\\b|didTapUnlock|LocalAuthentication|Touch ID|touch id|biometric|Face ID|face id|authenticate" . -g '*.swift'Repository: DevaultProject/Devault-macOS
Length of output: 5929
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Authentication service interface:"
sed -n '1,120p' ./Projects/DVDomain/Sources/Service/Interface/UserAuthenticationService.swift | cat -n
echo
echo "LockFeature references and delegates:"
rg -n "delegate\\(.*unlockCompleted|unlockCompleted\\)|LockFeature\\(|\\.lock|LockFeature\\.init|store: StoreOf<LockFeature>|StoreOf<LockFeature>" . -g '*.swift' | head -n 200
echo
echo "Lock files:"
fd -a 'Lock.*\.swift$' . | sed 's#^\./##'
echo
echo "User auth impl:"
sed -n '1,180p' ./Projects/DVData/Sources/ServiceImpl/Authentication/LocalUserAuthenticationServiceImpl.swift | cat -nRepository: DevaultProject/Devault-macOS
Length of output: 3157
unlockCompleted 전송을 인증 성공 결과로 바꾸세요.
didTapUnlock가 버튼을 누르는 즉시 delegate를 보내고 있어, 현재 UserAuthenticationService.authenticate가 호출되지 않습니다. LockFeature에서 LocalUserAuthenticationServiceImpl 의존성을 받아 인증을 트리거하고, 성공 시에만 unlockCompleted를 보냅니다. 실패/취소/미지원은 잠금 상태를 유지하거나 에러(delegate/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 `@Projects/DVPresentation/Sources/Features/Lock/LockFeature.swift` around lines
49 - 50, LockFeature의 didTapUnlock 처리에서 즉시 unlockCompleted를 보내지 말고
LocalUserAuthenticationServiceImpl 의존성을 주입해 authenticate를 호출하세요. 인증 성공 결과에서만
delegate unlockCompleted를 전송하고, 실패·취소·미지원 결과는 잠금 상태를 유지하거나 기존 에러 전달 경로로 처리하세요.
| var currentStepIndex: Int { | ||
| switch step { | ||
| case .welcome: return 0 | ||
| case .security: return 1 | ||
| case .icloudSync: return 2 | ||
| case .syncing: return 2 | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Syncing 단계를 네 번째 indicator로 표시하세요.
DVStepIndicator(totalSteps: 4, ...)를 사용하지만 .syncing이 2를 반환해 iCloud Sync 단계와 같은 세 번째 상태로 표시됩니다.
수정 예시
- case .syncing: return 2
+ case .syncing: return 3📝 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.
| var currentStepIndex: Int { | |
| switch step { | |
| case .welcome: return 0 | |
| case .security: return 1 | |
| case .icloudSync: return 2 | |
| case .syncing: return 2 | |
| } | |
| } | |
| var currentStepIndex: Int { | |
| switch step { | |
| case .welcome: return 0 | |
| case .security: return 1 | |
| case .icloudSync: return 2 | |
| case .syncing: return 3 | |
| } | |
| } |
🤖 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 `@Projects/DVPresentation/Sources/Features/Onboarding/OnboardingFeature.swift`
around lines 31 - 38, Update the currentStepIndex computed property so the
.syncing case returns index 3, making it the fourth indicator step while
preserving the existing indices for .welcome, .security, and .icloudSync.
| case .didTapEnableTouchID: | ||
| state.step = .icloudSync | ||
| return .none |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
Touch ID 성공 확인 후에만 다음 단계로 진행하세요.
현재 didTapEnableTouchID는 인증·등록 결과와 무관하게 즉시 iCloud Sync 화면으로 전환됩니다. 취소·실패 시에도 “Enable Touch ID”가 완료된 것처럼 진행되므로, 인증 클라이언트의 성공 콜백 또는 부모 delegate 이벤트를 받은 뒤 상태를 변경하세요.
🤖 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 `@Projects/DVPresentation/Sources/Features/Onboarding/OnboardingFeature.swift`
around lines 75 - 77, Update the didTapEnableTouchID handling in
OnboardingFeature so it advances to .icloudSync only after the authentication
client’s success callback or the parent delegate’s success event is received.
Keep the current step unchanged and avoid emitting the transition for canceled
or failed Touch ID attempts.
| case .didTapEnableSync: | ||
| state.step = .syncing | ||
| return .none | ||
|
|
||
| case .syncingCompleted: | ||
| return .send(.delegate(.completed)) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
실제 동기화 완료 이벤트를 연결하세요.
didTapEnableSync는 .syncing으로만 전환하고, 이 리듀서 내에서는 syncingCompleted를 보내는 효과가 없습니다. 따라서 사용자는 Syncing 화면에 계속 머뭅니다. 동기화 클라이언트를 의존성으로 주입해 성공 시 완료 delegate를 보내고, 실패·재시도 상태도 처리하세요. 원하시면 TCA effect 구조로 정리해드릴 수 있습니다.
🤖 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 `@Projects/DVPresentation/Sources/Features/Onboarding/OnboardingFeature.swift`
around lines 82 - 87, Connect the actual synchronization client to the
didTapEnableSync case, dispatching syncingCompleted only after a successful sync
so the existing completed delegate is reached. Handle synchronization failures
by updating the appropriate failure state and provide the retry path from the
syncing flow, using the feature’s existing TCA dependency and action/state
symbols.
| private extension SidebarFilter { | ||
| var iconColor: Color { |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="Projects/DVPresentation/Sources/Features/Sidebar/SidebarView.swift"
rg -n '^private extension SidebarFilter' "$file"
rg -n 'iconColor: filter\.iconColor' "$file"Repository: DevaultProject/Devault-macOS
Length of output: 248
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="Projects/DVPresentation/Sources/Features/Sidebar/SidebarView.swift"
printf '--- SidebarView.swift relevant lines ---\n'
sed -n '60,90p;170,192p' "$file" | cat -n
printf '\n--- Search for iconColor usages ---\n'
rg -n '\biconColor\b' "$file"Repository: DevaultProject/Devault-macOS
Length of output: 257
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="Projects/DVPresentation/Sources/Features/Sidebar/SidebarView.swift"
cat -n "$file" | sed -n '60,90p;170,192p'
printf '\n--- Search for iconColor usages ---\n'
rg -n '\biconColor\b' "$file"Repository: DevaultProject/Devault-macOS
Length of output: 2032
iconColor은 fileprivate extension에 두세요.
Line 78의 SidebarView가 다른 타입의 SidebarFilter.iconColor를 사용하는데, private extension의 멤버는 같은 타입의 extension 내부에서만 접근할 수 있습니다. 같은 파일의 SidebarView에서만 쓰므로 fileprivate extension이 허용하면서 가능한 만큼 좁은 범위입니다.
권장 수정
-private extension SidebarFilter {
+fileprivate extension SidebarFilter {📝 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.
| private extension SidebarFilter { | |
| var iconColor: Color { | |
| fileprivate extension SidebarFilter { |
🤖 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 `@Projects/DVPresentation/Sources/Features/Sidebar/SidebarView.swift` around
lines 183 - 184, Change the extension containing SidebarFilter.iconColor from
private to fileprivate so SidebarView can access the property within the same
file while keeping its visibility as narrow as possible.
Source: Path instructions
✨ What’s this PR?
📌 관련 이슈 (Related Issue)
🧶 주요 변경 내용 (Summary)
📸 스크린샷 (Optional)
🧪 테스트 / 검증 내역
💬 기타 공유 사항
컴포넌트 수정 및 배경 커스텀 수정자 추가
DVCategory:iconColor: Color파라미터 추가로 필터별 아이콘 색상 개별 지정 가능DVButton:primarySmall스타일 추가 (width 134, 나란히 배치되는 버튼에 사용)View+DVColor:dvScreenBackground()수정자 추가 — gray100 전체 배경 공통 처리🙇🏻♀️ 리뷰 가이드 (선택)
syncingCompleted액션은 추후 실제 iCloud sync 완료 콜백 시 연결 예정Summary by CodeRabbit
새로운 기능
개선 사항