feat: 폼 필드 컴포넌트 분리 및 구독 카드 인터랙션 개선

- billing_cycle_selector, category_selector, currency_selector 컴포넌트 분리
- 구독 카드 클릭 이슈 해결을 위한 리팩토링
- SMS 스캔 화면 UI/UX 개선 및 기능 강화
- 상세 화면 컨트롤러 로직 개선
- 알림 서비스 및 구독 URL 매칭 기능 추가
- CLAUDE.md 프로젝트 가이드라인 대폭 확장
- 전반적인 코드 구조 개선 및 타입 안정성 강화

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
JiWoong Sul
2025-07-14 15:47:46 +09:00
parent 2f60ef585a
commit 111c519883
39 changed files with 2376 additions and 1231 deletions

View File

@@ -9,6 +9,7 @@ import '../providers/theme_provider.dart';
import '../theme/adaptive_theme.dart';
import '../widgets/glassmorphism_card.dart';
import '../theme/app_colors.dart';
import '../widgets/native_ad_widget.dart';
class SettingsScreen extends StatelessWidget {
const SettingsScreen({super.key});
@@ -70,81 +71,18 @@ class SettingsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.only(top: 20),
children: [
// 테마 설정
GlassmorphismCard(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding: const EdgeInsets.all(8),
child: Consumer<ThemeProvider>(
builder: (context, themeProvider, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.all(16),
child: Text(
'테마 설정',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
// 테마 모드 선택
ListTile(
title: const Text('테마 모드'),
subtitle: Text(_getThemeModeText(themeProvider.themeMode)),
leading: Icon(
_getThemeModeIcon(themeProvider.themeMode),
color: Theme.of(context).colorScheme.primary,
),
trailing: DropdownButton<AppThemeMode>(
value: themeProvider.themeMode,
underline: Container(),
onChanged: (mode) {
if (mode != null) {
themeProvider.setThemeMode(mode);
}
},
items: AppThemeMode.values.map((mode) =>
DropdownMenuItem(
value: mode,
child: Text(_getThemeModeText(mode)),
),
).toList(),
),
),
const Divider(height: 1),
// 접근성 설정
SwitchListTile(
title: const Text('큰 텍스트'),
subtitle: const Text('텍스트 크기를 크게 표시합니다'),
secondary: const Icon(Icons.text_fields),
value: themeProvider.largeText,
onChanged: themeProvider.setLargeText,
),
SwitchListTile(
title: const Text('모션 감소'),
subtitle: const Text('애니메이션 효과를 줄입니다'),
secondary: const Icon(Icons.slow_motion_video),
value: themeProvider.reduceMotion,
onChanged: themeProvider.setReduceMotion,
),
SwitchListTile(
title: const Text('고대비 모드'),
subtitle: const Text('더 선명한 색상으로 표시합니다'),
secondary: const Icon(Icons.contrast),
value: themeProvider.highContrast,
onChanged: themeProvider.setHighContrast,
),
],
);
},
),
),
return Column(
children: [
SizedBox(
height: kToolbarHeight + MediaQuery.of(context).padding.top,
),
Expanded(
child: ListView(
padding: const EdgeInsets.only(top: 20),
children: [
// 광고 위젯 추가
const NativeAdWidget(key: ValueKey('settings_ad')),
const SizedBox(height: 16),
// 앱 잠금 설정 UI 숨김
// Card(
// margin: const EdgeInsets.all(16),
@@ -392,24 +330,6 @@ class SettingsScreen extends StatelessWidget {
),
),
// 데이터 관리
const GlassmorphismCard(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding: const EdgeInsets.all(8),
child: const Column(
children: [
// 데이터 백업 기능 비활성화
// ListTile(
// title: const Text('데이터 백업'),
// subtitle: const Text('구독 데이터를 백업합니다'),
// leading: const Icon(Icons.backup),
// onTap: () => _backupData(context),
// ),
// const Divider(),
],
),
),
// 앱 정보
GlassmorphismCard(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
@@ -485,11 +405,15 @@ class SettingsScreen extends StatelessWidget {
},
),
),
// FloatingNavigationBar를 위한 충분한 하단 여백
SizedBox(
height: 20 + MediaQuery.of(context).padding.bottom, // 하단 여백
height: 120 + MediaQuery.of(context).padding.bottom,
),
],
);
),
),
],
);
}
String _getThemeModeText(AppThemeMode mode) {