Skip to content

Refactor/appbar home widgets - #4

Merged
JEON-SEUNGBHIN merged 3 commits into
developfrom
refactor/appbar-home-widgets
Mar 8, 2026
Merged

Refactor/appbar home widgets#4
JEON-SEUNGBHIN merged 3 commits into
developfrom
refactor/appbar-home-widgets

Conversation

@wsw0922

@wsw0922 wsw0922 commented Mar 8, 2026

Copy link
Copy Markdown
Contributor

반영 브랜치

develop < refactor/appbar-home-widgets

  • 변경 요약
    홈 화면의 날짜 관련 로직과 위젯을 별도 모듈로 분리하고, 공통 AppBar인 DetailHeader를 추가해 UI 컴포넌트 재사용성과 코드 구조를 개선했습니다.

  • 주요 변경점

  • DetailHeader 컴포넌트 신규 추가(PreferredSizeWidget, title/트레일링/백버튼/배경색 지원)

  • 홈 화면에서 DateItem, EmptyOotdView 위젯을 별도 파일로 분리 및 사용

  • HomeDateUtils 유틸 추가: dateOnly, startOfWeek, weekDates, isSameDate, weekdayLabel 제공

  • home_screen.dart 내부의 사설 날짜 헬퍼/위젯 제거로 코드 간결화(+151줄 제거)

  • SettingScreen의 AppBar를 DetailHeader로 교체

  • 주의/리스크

  • DetailHeader의 높이(preferredSize)가 고정(48)되어 있어 화면별 디자인 요구에 따라 조정 필요

  • HomeDateUtils.weekdayLabel의 미매핑 입력은 빈 문자열을 반환해 UI 표시 이상 가능성

  • 새로운 위젯/유틸로 인한 import 경로 변경으로 다른 파일에서의 사용 누락 여부 점검 필요

  • 다음 액션

  • 프로젝트 전반에 DetailHeader 적용 대상 확인 및 일관성 적용

  • 홈 화면 날짜 동작 관련 단위/UI 테스트 추가 및 확인

  • 변경된 import/사용처(특히 홈 관련 위젯들)에서 빌드/런 타임 에러 없는지 검증

@wsw0922
wsw0922 requested a review from JEON-SEUNGBHIN March 8, 2026 09:58
@wsw0922 wsw0922 self-assigned this Mar 8, 2026
@coderabbitai

coderabbitai Bot commented Mar 8, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 577915ec-c5f5-426b-8d4a-da78ec719f20

📥 Commits

Reviewing files that changed from the base of the PR and between dbf3ed0 and 4bf1761.

📒 Files selected for processing (1)
  • lib/presentation/home/home_screen.dart

📝 Walkthrough

Walkthrough

새로운 DetailHeader 위젯을 추가하고, 홈 화면의 날짜 관련 내부 구현을 DateItem, EmptyOotdView, HomeDateUtils로 분리·공개하며, SettingScreen의 AppBar를 DetailHeader로 교체합니다.

Changes

Cohort / File(s) Summary
핵심 헤더 컴포넌트
lib/core/presentation/components/detail_header.dart
AppBar 래퍼인 DetailHeader PreferredSizeWidget 추가: title, trailing, backgroundColor, showBackButton, onBack 옵션과 고정 높이(48)를 제공.
홈 화면 진입부
lib/presentation/home/home_screen.dart
내부 날짜/빈뷰 구현을 외부 모듈로 대체하여 DateItem, EmptyOotdView, HomeDateUtils 사용하도록 변경; 관련 private 클래스/헬퍼 제거.
홈 유틸리티
lib/presentation/home/utils/home_date_utils.dart
HomeDateUtils 추가: dateOnly, startOfWeek, weekDates, isSameDate, weekdayLabel 제공.
홈 위젯들
lib/presentation/home/widgets/date_item.dart, lib/presentation/home/widgets/empty_ootd_view.dart
DateItem (선택 가능한 날짜 항목) 및 EmptyOotdView (빈 상태 표시 위젯) 신규 구현.
설정 화면
lib/presentation/setting/setting_screen.dart
기존 AppBar를 DetailHeader로 교체(뒤로가기 표시 비활성화), 관련 import 정리.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25분

Possibly related PRs

  • Feature/mypage UI #2: SettingScreen과 헤더 관련 변경이 겹치며 동일 UI 영역을 수정합니다.
  • Feature/home UI #3: lib/presentation/setting/setting_screen.dart의 AppBar 관련 수정 사항과 직접적인 코드 레벨 연관이 있습니다.

Suggested reviewers

  • JEON-SEUNGBHIN
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive PR 제목은 '설정' 화면의 AppBar를 DetailHeader로 교체하는 내용을 다루지만, 주요 변경사항인 홈 화면의 날짜 유틸리티 리팩토링, DateItem/EmptyOotdView 위젯 추출, HomeDateUtils 생성 등을 반영하지 않습니다. 제목을 'Extract home date utilities and widgets, refactor appbar usage' 또는 'Refactor home screen: extract date utilities and update app bars' 같이 변경하여 주요 변경사항을 포함하도록 수정하세요.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/appbar-home-widgets

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
lib/presentation/home/utils/home_date_utils.dart (1)

1-39: 정적 유틸 클래스는 인스턴스화를 막아 두는 편이 좋습니다.

지금 구조상 상태가 전혀 없는데 생성은 가능해서 의도가 흐려집니다. private constructor 하나만 추가해 두면 오용을 막을 수 있습니다.

가능한 수정 방향
 class HomeDateUtils {
+  const HomeDateUtils._();
+
   static DateTime dateOnly(DateTime date) => DateTime(date.year, date.month, date.day);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/presentation/home/utils/home_date_utils.dart` around lines 1 - 39,
HomeDateUtils is a purely static utility class but can be instantiated; add a
private constructor to prevent instantiation by declaring a private named
constructor (e.g., HomeDateUtils._();) inside the HomeDateUtils class so the
class cannot be constructed and only its static members (dateOnly, startOfWeek,
weekDates, isSameDate, weekdayLabel) are usable.
lib/core/presentation/components/detail_header.dart (1)

31-44: 기본 뒤로가기는 canPop 가드가 있는 편이 안전합니다.

공용 헤더인데 기본 분기에서 바로 context.pop()을 호출하고 있습니다. 루트 화면이나 pop 불가 컨텍스트에 붙으면 GoError: There is nothing to pop 예외가 발생하므로, 최소한 pop 가능 여부를 확인한 뒤 호출하는 쪽이 안전합니다.

수정 방향
         leading: showBackButton
           ? IconButton(
             padding: EdgeInsets.zero,
             constraints: const BoxConstraints(minWidth: 44, minHeight: 44),
             visualDensity: VisualDensity.compact,
-            onPressed: onBack ?? () => context.pop(),
+            onPressed: onBack ??
+                () {
+                  if (context.canPop()) {
+                    context.pop();
+                  }
+                },
             highlightColor: Colors.transparent,
             icon: const Icon(
               Icons.navigate_before,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/core/presentation/components/detail_header.dart` around lines 31 - 44,
The onPressed handler for the back IconButton currently calls context.pop()
directly (when onBack is null) which can throw if there is nothing to pop;
change the default handler in the IconButton (where showBackButton, onBack and
context.pop are used) to check pop capability first—e.g., replace the direct
context.pop() call with a guard that uses context.canPop() or
Navigator.canPop(context) (or GoRouter.of(context).canPop()) and only calls
context.pop() when true; keep onBack override behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/presentation/home/home_screen.dart`:
- Around line 19-23: The build recalculates today causing page/date mapping to
drift; freeze the initial basis date by computing today once with useMemoized
(no keys) and use that cached value for selectedDate, pageController
(_initialPage), and weekDates to ensure jumpToPage and onPageChanged use the
same fixed reference; update usages of today, selectedDate, pageController, and
weekDates to rely on the memoized initial date so page indices consistently map
to the correct dates across rebuilds.

In `@lib/presentation/home/widgets/empty_ootd_view.dart`:
- Around line 6-57: EmptyOotdView currently renders a tappable-looking "이미지 등록"
CTA but has no gesture handler; modify EmptyOotdView by adding an optional
VoidCallback (e.g., onTap) to its constructor, wrap the CTA Row (or the
Text/Icon pair) with an InkWell or GestureDetector inside build, and invoke
onTap when tapped; then update the caller (home_screen's const EmptyOotdView())
to pass the upload/start flow callback so tapping the CTA triggers the upload
flow.

---

Nitpick comments:
In `@lib/core/presentation/components/detail_header.dart`:
- Around line 31-44: The onPressed handler for the back IconButton currently
calls context.pop() directly (when onBack is null) which can throw if there is
nothing to pop; change the default handler in the IconButton (where
showBackButton, onBack and context.pop are used) to check pop capability
first—e.g., replace the direct context.pop() call with a guard that uses
context.canPop() or Navigator.canPop(context) (or GoRouter.of(context).canPop())
and only calls context.pop() when true; keep onBack override behavior unchanged.

In `@lib/presentation/home/utils/home_date_utils.dart`:
- Around line 1-39: HomeDateUtils is a purely static utility class but can be
instantiated; add a private constructor to prevent instantiation by declaring a
private named constructor (e.g., HomeDateUtils._();) inside the HomeDateUtils
class so the class cannot be constructed and only its static members (dateOnly,
startOfWeek, weekDates, isSameDate, weekdayLabel) are usable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3add4099-bd6e-49bd-a2e8-bee515ac18f4

📥 Commits

Reviewing files that changed from the base of the PR and between 3960bfd and dbf3ed0.

📒 Files selected for processing (6)
  • lib/core/presentation/components/detail_header.dart
  • lib/presentation/home/home_screen.dart
  • lib/presentation/home/utils/home_date_utils.dart
  • lib/presentation/home/widgets/date_item.dart
  • lib/presentation/home/widgets/empty_ootd_view.dart
  • lib/presentation/setting/setting_screen.dart

Comment thread lib/presentation/home/home_screen.dart Outdated
Comment on lines +6 to +57
class EmptyOotdView extends StatelessWidget {
const EmptyOotdView({super.key});

@override
Widget build(BuildContext context) {
return DottedBorder(
options: RoundedRectDottedBorderOptions(
color: ColorStyles.grayB8,
strokeWidth: 2,
dashPattern: const [6, 4],
radius: const Radius.circular(8),
),
child: Container(
decoration: BoxDecoration(
color: ColorStyles.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
spacing: 16,
children: [
Text(
'오늘의 OOTD를 등록하고\n룩티커를 만나보세요!',
textAlign: TextAlign.center,
style: TextStyles.normalTextMedium.copyWith(
color: ColorStyles.gray6B,
height: 1.4,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'이미지 등록',
style: TextStyles.smallTextBold.copyWith(
color: ColorStyles.pointC9,
),
),
const Icon(
Icons.chevron_right,
size: 16,
color: ColorStyles.pointC9,
),
],
),
],
),
),
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

이미지 등록 CTA에 실제 탭 동작을 연결해 주세요.

지금 UI는 액션처럼 보이지만 콜백/제스처가 없어서 lib/presentation/home/home_screen.dart Line 100의 const EmptyOotdView()에서는 업로드 플로우로 진입할 수 없습니다. 빈 상태의 핵심 액션이 막혀 있습니다.

가능한 수정 방향
 class EmptyOotdView extends StatelessWidget {
-  const EmptyOotdView({super.key});
+  final VoidCallback onTap;
+
+  const EmptyOotdView({
+    super.key,
+    required this.onTap,
+  });

   `@override`
   Widget build(BuildContext context) {
-    return DottedBorder(
-      options: RoundedRectDottedBorderOptions(
-        color: ColorStyles.grayB8,
-        strokeWidth: 2,
-        dashPattern: const [6, 4],
-        radius: const Radius.circular(8),
-      ),
-      child: Container(
-        decoration: BoxDecoration(
-          color: ColorStyles.white,
-          borderRadius: BorderRadius.circular(8),
-        ),
-        child: Column(
-          mainAxisSize: MainAxisSize.max,
-          mainAxisAlignment: MainAxisAlignment.center,
-          crossAxisAlignment: CrossAxisAlignment.center,
-          spacing: 16,
-          children: [
-            ...
-          ],
-        ),
-      ),
+    return Material(
+      color: Colors.transparent,
+      child: InkWell(
+        onTap: onTap,
+        borderRadius: BorderRadius.circular(8),
+        child: DottedBorder(
+          options: RoundedRectDottedBorderOptions(
+            color: ColorStyles.grayB8,
+            strokeWidth: 2,
+            dashPattern: const [6, 4],
+            radius: const Radius.circular(8),
+          ),
+          child: Container(
+            decoration: BoxDecoration(
+              color: ColorStyles.white,
+              borderRadius: BorderRadius.circular(8),
+            ),
+            child: Column(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              spacing: 16,
+              children: [
+                ...
+              ],
+            ),
+          ),
+        ),
+      ),
     );
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/presentation/home/widgets/empty_ootd_view.dart` around lines 6 - 57,
EmptyOotdView currently renders a tappable-looking "이미지 등록" CTA but has no
gesture handler; modify EmptyOotdView by adding an optional VoidCallback (e.g.,
onTap) to its constructor, wrap the CTA Row (or the Text/Icon pair) with an
InkWell or GestureDetector inside build, and invoke onTap when tapped; then
update the caller (home_screen's const EmptyOotdView()) to pass the upload/start
flow callback so tapping the CTA triggers the upload flow.

@JEON-SEUNGBHIN
JEON-SEUNGBHIN merged commit da3175b into develop Mar 8, 2026
3 checks passed
@JEON-SEUNGBHIN
JEON-SEUNGBHIN deleted the refactor/appbar-home-widgets branch March 8, 2026 22:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants