Files
submanager/doc/color.md
2025-09-16 14:30:14 +09:00

16 KiB

SubManager 컬러/테마 가이드 v4 (Glass 제거, 완전 Material 3)

목표: 글래스모피어즘(반투명/블러/그라데이션)을 전면 제거하고, 전 화면/버튼/팝업을 Material 3(ColorScheme/typography/shape/elevation) 기준으로 재정렬합니다. 버튼 나열 UI를 드롭다운으로 바꾸지 않습니다. 설정 화면에 라이트/다크/시스템 모드 선택 UI를 추가합니다.

0) 현재 상태 진단(요약)

  • 전역 테마: M3 사용 중(useMaterial3: true). 라이트/다크/OLED/고대비 테마 존재.
  • 이슈: ColorScheme.error가 핑크(danger)에 매핑 → 오류색으로 부적합(레드 필요).
  • Glass 사용처 다수(요약/분석/네비/빈상태 등): 반투명+블러+경계. 다크/저성능 장치에서 가독성·성능 저하 가능.
  • 곳곳의 하드코딩 텍스트 컬러(AppColors.darkNavy, Color(0xFF...)) 존재 → 다크에서 대비 문제 소지.

1) 원칙(신뢰·접근성·일관성)

  • 신뢰: Primary는 딥 블루(#2563EB). 과장된 장식 대신 명확한 위계/역할색 사용.
  • 접근성: 본문 대비 WCAG AA(4.5:1) 충족. on-colors(onPrimary/onSurface/onError…) 일관 적용.
  • 일관성: 전역 ColorScheme/typography/shape/elevation 우선, 로컬 styleFrom 최소화.
  • 성능/가독성: Glass 제거 → 불투명 Surface + elevation/outline 중심으로 레이어 구분.

2) 팔레트(최종)

  • Primary: #2563EB / onPrimary: #FFFFFF
  • Secondary: #60A5FA / onSecondary: #0B1B31(또는 onSurface)
  • Tertiary(Info): #6366F1 / onTertiary: #FFFFFF
  • Error: #EF4444 / onError: #FFFFFF
  • Success: #22C55E / Warning: #F59E0B (둘은 ColorScheme 외 확장 토큰으로 관리)
  • Light: Background #F1F5F9 / Surface #FFFFFF / SurfaceVariant #F8FAFC / OnSurface #1E293B / OnSurfaceVariant #334155 / Outline #E2E8F0
  • Dark: Background #121212 / Surface #1E1E1E / OnSurface #F5F5F6 / OnSurfaceVariant #94A3B8 / Outline #3F3F46

3) 타입·라디우스·간격·음영 스케일

  • Typography(권장):
    • displayLarge 48 / displayMedium 40 / displaySmall 34
    • headlineLarge 32 / headlineMedium 28 / headlineSmall 24
    • titleLarge 20 / titleMedium 18 / titleSmall 16
    • bodyLarge 16 / bodyMedium 14 / bodySmall 12
    • labelLarge 14 / labelMedium 12 / labelSmall 11
    • Line-height: 1.31.5, Letter-spacing: 헤드라인(-0.2-0.5), 본문(+0.1)
  • Shape: 4(칩/태그) / 8(스위치/토글) / 12(버튼/입력) / 16(카드/시트)
  • Elevation: 0(평면) / 1(구분) / 3(카드) / 6(상부 시트/다이얼로그)
  • Spacing: 4 단위(8/12/16/24/32)로 수직 리듬 고정

4) Glass 제거 및 대체 규칙

  • lib/widgets/glassmorphism_card.dart 사용부 전면 치환:
    • 대체: Card(elevation: 3, color: colorScheme.surface, shape: 16)
    • 경계: Outline 기반(라이트 #E2E8F0, 다크 #3F3F46, 투명도 60~80%)
    • 섀도우: 라이트만 약하게(8~12), 다크는 outline 위주
  • 내부 텍스트: 항상 colorScheme.onSurface 또는 전역 textTheme 사용(하드코딩 금지)
  • 그라데이션/반투명 배경 삭제(필요 시 Hero/그림·아이콘 등으로 시각적 흥미 보완)

5) 컴포넌트별 가이드(누락 없음)

  • AppBar: 배경=surface, 제목/아이콘=onSurface, 높이=56, 타이틀 글꼴=titleLarge
  • Navigation(하단): 배경=surface, 활성 아이콘/라벨=primary, 비활성=onSurfaceVariant, 반경=16
  • FAB: 배경=primary, 아이콘=onPrimary, 반경=16, elevation=6
  • Buttons(Elevated/Text/Outlined): minHeight=48, 반경=12, primary=onPrimary, outline=outline, text=onSurface
  • IconButton: 기본 onSurface, 강조 상태는 primary 80~90%
  • Inputs(TextField/Selectors): filled 라이트=surfaceVariant, 다크=#2A2A2A, 포커스라인=primary 1.5, 에러=error 1.5~2
  • Chips/Badges: 배경=역할색(primary/success/warning/error), 텍스트=onX, 반경=8
  • Cards: elevation=3, 반경=16, 배경=surface, 텍스트=onSurface
  • Lists/Tiles: 제목=onSurface, 보조=onSurfaceVariant, divider=outline, 타일 반경=12
  • Dialogs/Sheets: 배경=surface, 제목=titleLarge, 본문=bodyMedium, 버튼=역할색+onX, elevation=6, 반경=20
  • Snackbar: 배경=역할색(primary/success/warning/error), 텍스트/아이콘=onX, 모서리=12, floating
  • Tooltips: 배경=onSurface, 텍스트=surface, 반경=8
  • Progress: primary 사용, 트랙=onSurfaceVariant
  • Charts/Analysis: 팔레트 [primary, tertiary(info), success, warning, error, secondary], 라벨=onSurface
  • Categories/SMS: 카테고리 배경 위 텍스트/아이콘은 대비 계산(white 또는 onSurface) 적용

6) 설정 화면에 모드 선택 UI 추가(계획)

  • 위치: lib/screens/settings_screen.dart
  • 섹션명: Appearance(또는 테마)
  • 구성: Theme Mode 라디오 그룹(시스템 / 라이트 / 다크)
    • RadioListTile 3개(버튼 나열 유지, 드롭다운 금지)
    • 값: AppThemeMode.system|light|dark
    • 동작: context.read<ThemeProvider>().setThemeMode(mode) 호출
  • 추가 토글(유지): 큰 텍스트/모션 감소/고대비(현 Provider 연동)

샘플 코드

final themeProvider = context.read<ThemeProvider>();
Column(children: [
  ListTile(title: Text('Theme Mode')),
  RadioListTile(
    title: Text('System'),
    value: AppThemeMode.system,
    groupValue: themeProvider.themeMode,
    onChanged: (v) => themeProvider.setThemeMode(v!),
  ),
  RadioListTile(
    title: Text('Light'),
    value: AppThemeMode.light,
    groupValue: themeProvider.themeMode,
    onChanged: (v) => themeProvider.setThemeMode(v!),
  ),
  RadioListTile(
    title: Text('Dark'),
    value: AppThemeMode.dark,
    groupValue: themeProvider.themeMode,
    onChanged: (v) => themeProvider.setThemeMode(v!),
  ),
]);

7) 적용 순서(리스크 최소)

  1. 전역 스킴 교정: ColorScheme.error 레드로, textTheme onSurface 정렬
  2. Glass 제거: GlassmorphismCardCard 치환(화면 단위 PR: 홈→분석→설정→세부)
  3. 버튼/입력/스낵바/다이얼로그 on-colors 정렬, 하드코딩 텍스트 제거
  4. 모드 선택 UI 추가(설정 화면 라디오 그룹)
  5. 카테고리/차트 대비 보정 유틸 적용
  6. 회귀·접근성 검증(라이트/다크/시스템)

8) 검증

  • 스크립트: scripts/check.sh (format/analyze/test)
  • 시각: 모든 화면에서 텍스트 대비(AA) 확인, 상태(Hover/Pressed/Disabled) 점검
  • 성능: Glass 제거 후 저사양 단말 스크롤/애니메이션 프레임 확인

9) 요약

  • Glass 제거 + 완전 Material 3 전환으로 신뢰감, 가독성, 성능을 함께 강화합니다.
  • 오류색은 레드로 통일, on-colors로 대비를 보장합니다.
  • 설정에 시스템/라이트/다크 선택을 제공하고, 버튼 나열 UI는 유지합니다.

진행 현황(Work Log)

  • [완료] 전역 스킴 교정: ColorScheme.error를 레드(#EF4444)로 교정 (라이트/다크)
  • [완료] 스낵바 오류색 정렬: AppSnackBar.showErrorcolorScheme.error 사용
  • [완료] 설정 화면 테마 모드 UI: System/Light/Dark SegmentedButton 추가(드롭다운/라디오 대체, M3 준수)
  • [완료] Glass 제거(설정 화면): GlassmorphismCardCard 치환
  • [완료] Glass 제거(빈 상태 위젯): EmptyStateWidgetCard 기반으로 재구성
  • [완료] Glass 제거(홈 요약 카드): MainScreenSummaryCard 외곽 → Card
  • [완료] Glass 제거(분석 카드): 월간 지출/총지출/파이차트 카드 → Card
  • [완료] Glass 제거(광고 카드): NativeAdWidgetCard
  • [완료] Glass 제거(추가 폼 섹션): AddSubscriptionFormCard
  • [완료] Glass 제거(SMS 권한 화면): 설명 카드 → Card
  • [완료] Glass 제거(네비게이션): Floating Navigation Bar → Container + Padding(Material 기준)
  • [완료] Glass 제거(메인 스캐폴드): GlassmorphicScaffold → Stack+Scaffold(배경 그라디언트+M3)
  • [진행] Glass 제거(기타): 일부 카드(예: SubscriptionCard) 잔여 사용처 점진 치환 예정
  • [완료] Glass 제거(구독 카드): SubscriptionCard 래퍼를 Material Card+InkWell로 대체
  • [진행] 하드코딩 텍스트 컬러 제거: 메인 요약/URL 섹션/네비/홈 로딩 인디케이터 등 onSurface/onSurfaceVariant로 정렬
  • [진행] 하드코딩 컬러 정리(추가): 카테고리 관리/앱 잠금/이벤트·URL 상세 섹션 컨테이너와 텍스트를 M3(surface, outline, onSurface)로 정렬
  • [진행] 폼/셀렉터 M3 정렬: DatePickerField/CurrencySelector 색을 onSurface/primary/surfaceVariant로 통일
  • [진행] Selectors: Category/BillingCycle 선택 컴포넌트의 배경/텍스트를 primary/onSurface로 정렬
  • [진행] 공통 입력/라벨: BaseTextField/DatePickerField 라벨·힌트·값을 onSurface/onSurfaceVariant로 정렬
  • [진행] 삭제 다이얼로그: Glass 제거, Material Dialog(표면/elevation) + on-colors 적용
  • [진행] 추가 화면: 이벤트 섹션 타이틀/설명을 onSurface로 정렬
  • [진행] 날짜 필드(DatePicker/Range): 라벨/값/아이콘/컨테이너를 M3 surface/outline/onSurface 계열로 치환
  • [진행] 분석 카드/리스트: 보조 텍스트/경계/아이콘을 onSurfaceVariant/primary 계열로 정리
  • [진행] 설정 화면: 텍스트/아이콘 색을 onSurface/onSurfaceVariant로 정리
  • [진행] SMS 권한 화면: 아이콘/제목/본문을 primary/onSurface/onSurfaceVariant로 정리
  • [진행] 추가 화면 AppBar/저장 버튼: 색을 onSurface/primary로 정리
  • [다음] 버튼/입력/다이얼로그/스낵바의 on-colors 재점검 및 하드코딩 텍스트 컬러 제거

2025-09-10 작업 메모(Incremental)

  • [완료] Settings 화면: AppColors.* 제거 → colorScheme.primary/onSurface/onSurfaceVariant 적용. 알림 반복 SwitchListTile의 activeColor 비사용(신 API activeThumbColor/activeTrackColor)로 교체.
  • [완료] AddSubscriptionForm: CurrencySelector / BillingCycleSelector / CategorySelector의 isGlassmorphism 플래그 비활성(기본 M3 경량 스타일 사용).
  • [완료] MainSummaryCard: 이벤트 절약액 텍스트 색상을 colorScheme.primary로 정렬.
  • [완료] MonthlyExpenseChartCard: 툴팁 배경/텍스트를 inverseSurface/onInverseSurface로 교체(가독성 향상).
  • [완료] Light Theme 카드/입력: lib/theme/app_theme.dart의 카드 테마에서 글래스 컬러/보더 제거, elevation=1·radius=16 유지. InputDecorationTheme는 surfaceVariant(light 대체 토큰) + outline/primary/error 경계로 전환.
  • [완료] TotalExpenseSummaryCard: 아이콘 캡슐 배경을 surfaceContainerHighest+outline로 교체, 아이콘 컬러는 primary 사용. 복사 스낵바의 글래스 배경 제거.
  • [완료] DetailFormSection: 글래스 박스 → surface + outline 컨테이너로 교체, Currency/BillingCycle/Category 셀렉터의 isGlassmorphism 비활성.
  • [완료] SMS Scan SubscriptionCard: Card(elevation:1, outline)로 교체, forceDark 텍스트 제거, 입력 fillColorsurface로 통일, 카테고리 셀렉터 글래스 비활성.
  • [완료] SecondaryButton: Hover 배경을 onSurface 6%로, 보더/텍스트를 outline/primary로 정렬.
  • [완료] CategoryManagement: AppBar primary/onPrimary 적용, Dropdown value→initialValue(비권장 API 해결), 텍스트 onSurface 정렬.
  • [완료] Primary/SecondaryButton hover 트랜스폼: Matrix4.scale 제거 → diagonal3Values 또는 Transform.scale로 대체(비권장 API 해결).
  • [완료] RotatePageRoute 전환: Matrix4.scale 제거 → 중첩 Transform.scale로 전환.
  • [완료] ThemedText: AppColors 의존 제거, 대비 색상 결정을 colorScheme.onSurface 기반으로 단순화.
  • [완료] 글래스 파일 제거: lib/widgets/glassmorphism_card.dart, lib/widgets/glassmorphic_scaffold.dart 삭제(미참조 확인).
  • [완료] Light Theme 텍스트·컴포넌트 정렬: app_theme.dart에서 textTheme를 M3 기본 + onSurface 컬러로 일괄 정렬. Switch/Checkbox/Radio/Slider/TabBar/Divider를 ColorScheme 기반으로 리팩터.
  • [완료] AddSubscriptionAppBar: const 적용(경고 제거), scripts/check.sh 전체 통과 확인.
  • [완료] Dark/OLED 테마 정리: adaptive_theme.dart에서 다크 텍스트·컴포넌트(M3 on-colors) 정렬, Input/Buttons/TabBar/Divider/Switch/Checkbox/Radio/Slider를 ColorScheme 기준으로 통일. OLED는 surface/배경만 블랙 톤으로 보정.
  • [완료] ThemedText: Glass 마커 제거(Indicator/Wrapper 삭제), 대비 로직 단순화.
  • [완료] Charts: 월간 바차트 색상 ColorScheme.primary/secondary로 전환, 그리드/백바 onSurfaceVariant 사용. 파이차트 팔레트는 ColorScheme(primary/secondary/tertiary/error)+success/warning 상수로 정리.
  • [완료] Settings/SubscriptionCard: 글래스 위젯 의존 제거 → Material Card + InkWell로 치환(중첩 Padding은 ListTile의 contentPadding 사용).
  • [완료] Settings 색 정리 마무리: 모든 텍스트/아이콘/보더/드롭다운을 onSurface/onSurfaceVariant/primary/surface로 통일.
  • [완료] 전역 그라데이션 제거: EmptyState/FloatingNav Add/MainSummary 이벤트 배지/Detail Header/Detail 편집 안내/SubscriptionCard 헤더·이벤트 배지/Add 화면 헤더/Splash 배경, 로고/파티클 장식 등 모든 Linear/Radial gradient 삭제. 단색은 primary/surface/surfaceContainer*/semantic(error, warning)로 대체.
  • [완료] 차트 막대 그라데이션 제거: 단색 primary로 통일.
  • [검증] scripts/check.sh 실행: 포맷 자동 적용 후 정적 분석 info 수준 경고만 존재(주요 activeColor 비권장 항목 해결됨).

2025-09-11 작업 메모(Incremental)

  • [완료] BillingCycleSelector: 선택 배경=primary, 텍스트=onPrimary, 비선택 배경=surface, 보더=outline(60%); glass/gradient 파라미터는 비사용 처리(호환 유지).
  • [완료] CurrencySelector: 동일한 M3 패턴으로 정리(표면/윤곽선/온컬러), isGlassmorphism 무시.
  • [완료] CategorySelector: 선택 시 baseColor가 있으면 사용, 없으면 primary; 나머지는 surface/outline/onSurface.
  • [완료] AnalysisBadge: AppColors 제거 → surface 배경 + outline 보더 + 은은한 블랙 섀도(8%).
  • [완료] SubscriptionCard:
    • 상단 스트립: event=error, 결제 임박=warning, 그 외=카테고리 색.
    • 가격: 이벤트 원가=onSurfaceVariant 취소선, 현재가=error, 일반가=primary.
    • 결제 예정 뱃지: success/warning(확장 토큰) 사용, 배경은 10% 알파.
    • 결제 주기 뱃지: surface + outline, 텍스트 onSurfaceVariant.
  • [검증] scripts/check.sh 전체 통과(Format/Analyze/Test OK).

2025-09-11 추가 배치

  • [완료] AppLock/Main 화면 스낵바: ColorScheme.error/success + onPrimary 텍스트로 통일.
  • [완료] AddSubscriptionEventSection: info 박스 tertiary로, 아이콘도 동일 컬러.
  • [완료] DetailEventSection: 초록 상수 제거 → colorScheme.success/onPrimary.
  • [완료] SMS Scan 위젯: 로딩 인디케이터/버튼을 primary 기반으로.
  • [완료] SubscriptionPieChartCard: AppColors 제거, 팔레트는 primary/success/warning/error/tertiary/secondary + 화이트 라벨. 환율 배지는 primary 소프트 톤.
  • [완료] EventAnalysisCard: 현재가/할인율 배지 색을 success/error로 정리.
  • [완료] TotalExpenseSummaryCard: 아이콘을 success로 정리.
  • [완료] Splash: overlay/파티클/타이틀/서브타이틀/인디케이터를 ColorScheme 기반으로 단순화(파티클 색은 렌더 시 primary).
  • [검증] scripts/check.sh 재실행 통과.

2025-09-11 Dark Theme 정리

  • [완료] adaptive_theme.dart 다크 테마를 전면 ColorScheme 기반으로 재정렬:
    • InputDecorationTheme: fill=surface, border=outline/primary/error, label/hint=onSurfaceVariant.
    • Elevated/Switch/Checkbox/Radio/Slider/TabBar/Divider: scheme 값 사용.
    • AppBar/Card: 배경=surface, 전경/테두리=scheme on/outline.
    • OLED 테마는 surface만 더 어둡게 덮어쓰기.
  • [검증] scripts/check.sh 통과.

2025-09-11 Light Theme 추가 정리

  • [완료] app_theme.dart 라이트 테마를 ColorScheme 기반으로 정리:
    • InputDecorationTheme: fill=surface, border=outline/primary/error, label/hint=onSurfaceVariant.
    • Elevated/Text/Outlined/FAB: primary/onPrimary, Outlined 보더=outline.
    • SnackBarTheme: primary/onPrimary.
    • Scaffold 배경은 기존 디자인(#F1F5F9)을 유지(직접 지정).
  • [검증] scripts/check.sh 재실행 통과.